Django - serializing queryset along with related models - json

There are hundreds of posts related to an elementary goal.
I have a simple model:
class ModelA(models.Model):
# I've got only two fields in reality,
# but let's suppose there are 150 of them
class ModelB(models.Model):
# fields
class ModelC(models.Model):
field_c = Integer
modelA = models.ForeignKey('ModelB')
modelB = models.ForeignKey(ModelC)
model_c_instance = ModelC.objects.select_related().get(pk=pk)
All I want to do is to come up with a JSON object which would include the fields for ModelA and ModelB.
Wadofstaff (post) does not suit for Django 1.7 and higher.
This post does not shed light on how I should serialize the objects.
This post tell about Full Serializers, but there's no code snippet to see how it is used.
My final JSON object should look like
[{
"model": "userinfo",
"fields": {
"field_c ": "9966",
"modelA": [{
# modelA fields
}
etc...
}]
Do I need REST framework ? Or Full Serializers ?
Please could anyone suggest a structured answer to this topic. I can't come up with a solution for two weeks.

You want to use a nested relationship. You don't show anything about the userinfo model so this answer doesn't take that into account. You could do something similar to this pseudo-code:
# serializers.py
from rest_framework import serializers
class ModelASerializer(serializers.ModelSerializer):
class Meta:
model = ModelA
class ModelBSerializer(serializers.ModelSerializer):
class Meta:
model = ModelB
class ModelCSerializer(serializers.ModelSerializer):
modelA = ModelASerializer(many=True)
modelB = ModelBSerializer(many=True)
class Meta:
model = ModelC

Related

How do I implement polymorphic dataclass models with default values in the base model in SQLAlchemy 2.0 / Declarative?

I'm in the process of migrating to SQLAlchemy 2.0 and adopting new Declarative syntax with MappedAsDataclass. Previously, I've implemented joined table inheritance for my models. The (simplified) code looks like this:
from sqlalchemy import ForeignKey, String
from sqlalchemy.orm import DeclarativeBase, Mapped, MappedAsDataclass, mapped_column
class Base(MappedAsDataclass, DeclarativeBase):
pass
class Foo(Base):
__tablename__ = "foo"
id: Mapped[int] = mapped_column(primary_key=True)
type: Mapped[str] = mapped_column(String(50))
foo_value: Mapped[float] = mapped_column(default=78)
__mapper_args__ = {"polymorphic_identity": "foo", "polymorphic_on": "type"}
class Bar(Foo):
__tablename__ = "bar"
id: Mapped[int] = mapped_column(ForeignKey("foo.id"), primary_key=True)
bar_value: Mapped[float]
__mapper_args__ = {"polymorphic_identity": "bar"}
The important bit for the question is the default value in foo_value. Because of its presence, a TypeError: non-default argument 'bar_value' follows default argument is raised. While moving fields around in the definition of a single class could make this error go away (but why is it raised in first place, since the field order is not really important?), it's not possible with inherited models.
How can I fix or work around this limitation? Am I missing something relevant from the documentation?
It seems I needed to use insert_default with MappedAsDataclass instead of default, as described in the docs.

Python Sqlalchemy Question - what is the class DicMixIn to Class Records?

I am very new to Python and SqlAlchemy. I stumbled upon this code while learning using SqlALchemy with Flask. Can you please help me to understand the class DictMixIn class - what are we doing here? Why are we using this?
class DictMixIn:
def to_dict(self):
return {
column.name: getattr(self, column.name)
if not isinstance(
getattr(self, column.name), (datetime.datetime, datetime.date)
)
else getattr(self, column.name).isoformat()
for column in self.__table__.columns
}
class Record(Base, DictMixIn):
__tablename__ = "Records"
id = Column(Integer, primary_key=True, index=True)
date = Column(Date)
country = Column(String, index=True)
cases = Column(Integer)
deaths = Column(Integer)
recoveries = Column(Integer)
At the end, the following snipped code was used - I believe they are using to_dict function above to print it. Am I right?
def show_records():
records = app.session.query(models.Record).all()
return jsonify([record.to_dict() for record in records])
The original code is here - https://github.com/edkrueger/sars-flask
I would really appreciate your help.
A mixin let's you add methods and properties to a class outside of the direct class hierarchy. You can then use the same mixin to inject methods/properties into many classes, ie. preventing duplication by not writing that same to_dict() into each database model. This mixin helps extend model classes in this case but this pattern is a python pattern and not specific to SQLAlchemy.
This specific mixin just lets you convert a database model instance into a simple dictionary. It seems that the intent as you pointed out is to jsonify a database model instance. JSON does not support Dates so that is why special care is taken to convert datetimes into a str with isoformat().
record.to_dict() might output something like:
{
"id": 100,
"date": "2021-09-11"
"country": "USA",
"cases": 100000000,
"deaths": 600000,
"recoveries": 95000000
}
mixin explained on stackoverflow
multiple inheritance in python docs -- the mixin pattern utilizes multiple inheritance in Python

DJANGO ListView returns HTTPResponse, but I need a json

I am having a problem around the Class Based Views in Django. I need to create JSON responses, instead of rendering to a template.
class AllItem(ListView):
model = MyModel
context_object_name = 'items'
template_name = 'mymodel/index.html'
I also have a serializer class
class SpendingConfigSerializer(serializers.ModelSerialier):
class Meta:
model = SpendingConfig
fields = ('record_date', 'amount', 'name')
Does anyone know how to connect them?
Thanks
Z.
You can make use of a ListAPIView and specify your SpendingConfigSerializer as serializer:
from rest_framework import generics
class UserList(generics.ListCreateAPIView):
queryset = SpendingConfig.objects.all()
serializer_class = SpendingConfigSerializer

Unable to serialize a nested python object using json.dumps()

I am new to python so sorry about the naive questions. I have a simple code snipper where I try to serialize a python object to a dictionary using json.dumps()
import json
class Document:
uid = "1"
content = "content1"
domain = "domain"
title = "title"
class ASSMSchema:
requestSource = "unittest"
documents = []
def entry():
myObj = ASSMSchema()
myObj.requestSource = "unittest"
document1 = Document()
document1.uid = "1"
document1.content = "content1"
document1.domain = "domain"
document1.title = "title"
myObj.documents.append(document1)
print(json.dumps(myObj.__dict__))
if __name__ == "__main__":
entry()
I get the following output when I run the above code
{"requestSource": "unittest"}
This is not expected however, since it should also seralize the List of "Document" objects. Appreciate your answers. Thanks in advance!
Your class definition of ASSMSchema defines the class members documents and requestSource. These are not attributes of a single instance of this class, but shared between all instances. When you are running myObj.requestSource = "unittest", you are defining a member variable on the instance myObj. This member is actually reflected in the output of json.dumps, whereas the class members (like documents) are not.
For further reading, see https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables
Depending on the complexity and desired maintainability of your program, there are multiple approaches to archieve your desired behaviour. Firstly, you have to fix the mistake in both class definitions. To define a class with instance variables instead of class variables, do something like this:
class Foo:
# class variables go here
def __init__(self, field1, field2):
# This method is called when you write Foo(field1, field2)
# these are instance variables
self.field1 = field1
self.field2 = field2
If you want to dump this class as JSON, you can simply use the trick with __dict__: print(json.dumps(Foo(1,2).__dict__)) will output something like { "field1": 1, "field2": 2 }.
In your case, there is the documents member though, which is not JSON serializable by default. Therefore, you must handle this separately as well. You could write an encoder for your ASSMSchema (see this thread for more info on that). It could be implemented roughly like this:
from json import JSONEncoder
class ASSMSchemaEncoder(JSONEncoder):
def default(self, o):
return {
"requestSource": o.requestSource,
# Convert the list of Document objects to a list of dict
"documents": [d.__dict__ for d in o.documents]
}
Now, when serializing an instance of ASSMSchema, this implemention is used and the documents member is replaced with a list of dictionaires (which can be serialized by the default encoder). Note, that you have to specify this encoder when calling json.dumps, see the linked thread above.

How to make QuerySet JSON serializable?

I have a problem with creating a new object in my Rest Framework.
As much I as understand, when I tried to overwrite item's field so it could have all the items that are in my database. I thought, that this would work, and it showed me the working page and I could choose an item. But when I tried to post it to create a new object, it said "Object of type 'Item' is not JSON serializable"
I was trying to figure it out, how to convert Item.objects.all() into JSON data. But nothing helped me. I understand, that this isn't really hard to do, but I can't figure it out on my own.
So I ask for your help, how to solve this problem?
Here's my serializer
from rest_framework import serializers
from items.models import OrderItem, Item
class OrderItemSerializer(serializers.ModelSerializer):
item = serializers.ChoiceField(choices=Item.objects.all())
class Meta:
model = OrderItem
fields = ('item', 'size', 'quantity', 'id')
from rest_framework import serializers
from items.models import OrderItem, Item
class OrderItemSerializer(serializers.ModelSerializer):
item = serializers.SerializerMethodField()
class Meta:
model = OrderItem
fields = ('item', 'size', 'quantity', 'id')
def get_item (self, obj):
# in value list name all fields u want or empty for defaults
return Item.objects.all().values_list('pk', flat=True)
...
and inside the create method (post in Serializer)
...
def create(self, validated_data):
req = self.context.get('request')
items = req.data.get('item')
if items:
[OrderItem.item.add(
oneitem) for oneitem in items]