nested serialize Django object - django

hi guys i want to serialize my model's object. and my model like this :
class User (models.Model):
name = models.CharField(max_length=30)
family_name = models.CharField(max_length=30)
and i have another model like this:
class Child (models.Model):
little_name = models.CharField(max_length=30)
user = models.ForeignKey("User", on_delete=models.CASCADE,)
i want to serialize one of my child object with all fields in user field for example like this:
{"id": 1 ,
"little_name": "Sam",
"user": {"id": 1,
"name": "Karim",
"family_name":"Kari"
}
}
i use model_to_dict() and dict() and serializer of django but i can't get user field compeletly and they return it like this :
{"id": 1 ,
"little_name": "Sam",
"user": "id": 1,
}
and i don't want to use django rest serializer
what can i do ?!?

Use model_to_dict twice:
child_dict = model_to_dict(child)
child_dict['user'] = model_to_dict(child.user)

Related

How do you post data in django with attribute depth=1 in the serializer?

I have a django model called “Enrolment” that depends on two other models through foreign key. “Course” model and “Enrolment” model. The “Course” model is like so:
class Course(models.Model):
name = models.CharField(max_length=100, blank=True)
description = models.TextField(blank=True)
prerequisite = models.TextField(blank=True)
fee = models.FloatField(default=0.0)
def __str__(self):
return self.name
And the Enrolment model is like so:
class CourseEnrolment(models.Model):
course_name = models.ForeignKey(
Course, on_delete=DO_NOTHING)
schedule = models.CharField(max_length=50, blank=True)
student = models.ForeignKey(
UserAccount, on_delete=DO_NOTHING)
enrolment_date = models.DateTimeField(default=datetime.now())
def __str__(self):
return self.course_name.name
For me to gain access to the information about the enrolled course, I have to do like so in the CourseEnrolmentSerializer:
class CourseEnrolmentSerializer(serializers.ModelSerializer):
class Meta:
model = CourseEnrolment
depth = 1
fields = '__all__'
With “depth = 1” being the secret to accessing information about the course. Now when I fetch enrolment, I get a response like below, which is exactly what I want like so.
{
"id": 5
"schedule": "June 23, 2022",
"course_name": {
"id": 4,
"name": "fundamentals-of-programming",
"description": "some description .",
"prerequisite": "some prerequisite",
"fee": 1000,
},
"student": {
"id": 1,
"email": "martinsakinbo#yahoo.com",
"first_name": "John",
"last_name": "Doe",
"phone": "1111111",
}
},
Now, the problem I have is that with “depth=1” in the serializer, I’m not able to create an enrolment when I write the following view
class CourseEnrolment(generics.CreateAPIView):
queryset = CourseEnrolment.objects.all()
serializer_class = CourseEnrolmentSerializer
Trying to create enrolment in postman by doing like so:
{
"course_name": 3,
"schedule": "June 23, 2022",
"student": 1
}
Generates the error the “null value in column "course_name_id" of relation "course_courseenrolment" violates not-null constraint”
I equally tried by nesting into the course_name id and student id by doing like so:
{
"course_name.id": 3,
"schedule": "June 23, 2022",
"student.id": 1
}
I get the same error.
But if I remove depth=1 from the serializer, everything works, and I’m about to create an enrolment
PLEASE HOW DO I CREATE (POST) AN ENROLMENT STILL WITH “depth=1”? OR IS THERE A BETTER OR DIFFERENT WAY I SHOULD WRITE MY VIEW. IF YES, HOW?
Make a new serializer specific for creating course enrollment:
class CreateCourseEnrollmentSerializer(serializers.ModelSerializer):
class Meta:
model = CourseEnrolment
fields = "__all__"
And inside the view define get_serializer_class() method in the following way (which you may want to use if your view supports more the one HTTP action. Actions are available to rest_framework.viewsets):
from rest_framework import viewsets
from .serializers import CreateCourseEnrollmentSerializer, CourseEnrolmentSerializer
class CourseEnrollmentView(viewsets.ModelViewSet):
# ...
def get_serializer_class(self):
if self.action == "create":
return CreateCourseEnrollmentSerializer
return CourseEnrolmentSerializer
And in the app's urls.py:
from .views import CourseEnrollmentView
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r"course-enrollments", CourseEnrollmentView)
urlpatterns = [
# ...
]
urlpatterns += router.urls

How to make dynamic field serializer in Django RestFramework

I want to add Dynamic Field Array serializer in my drf project:
My get response looks something like this:
{
"title": "some",
"created_at": "2022-03-06T15:59:52.684469Z",
"fields": [
{
"id": 1,
"title": "Some title?",
"parent_field": 1
},
{
"id": 2,
"title": "Yet another fields",
"parent_field": 1
}
]
}
This is the item detail serializer, and fields is another model serializer. I achieved this by using this code:
class AnotherFieldSerializer(serializers.ModelSerializer):
class Meta:
model = AnotherModel
fields = "__all__"
class FirstSerializer(serializers.ModelSerializer):
fields = serializers.SerializerMethodField()
class Meta:
model = FirstModel
fields = "__all__"
def get_fields(self, obj):
serializer_context = {'request': self.context.get('request')}
children = obj.fields
if not children.exists():
return None
serializered_children = FirstSerializer(
children,
many=True,
context=serializer_context
)
return serializered_children.data
This works only for GET requests I want this to also work with POST and PUT requests. So, imagine I want to add/edit an item into my model FIRST model and add fields associated with it by just sending this JSON:
{
"title": "some",
"created_at": "2022-03-06T15:59:52.684469Z",
"fields": [
{
"id": 1,
"title": "Some title?",
},
{
"id": 2,
"title": "Yet another fields",
}
]
}
I know I can get fields from the response and loop through each item to create an instance of Another Model but fields validation will be much harder I think. But if there's more of a drf of doing this thing then it would be great. Also, I have no problem with making another serializer just for POST and PUT requests.
I hope my English was understandable.
You can create a new serializer for validation. To validate multiple items you can do the following,
class PostSerializer(serializers.Serializer):
title = serializers.CharField(max_length=200)
created_at = serializers.DateTimeField()
fields = FirstSerializer(many=True) # your model serializer for the FirstModel
Ref : https://www.django-rest-framework.org/api-guide/serializers/#listserializer

Django serializer field not working

I did not find a solution although I looked at the questions asked...
When I use this serializer:
class MessageSerializer(ModelSerializer):
sender = UserMobileSerializer(read_only=True)
class Meta:
model = Messages
fields = '__all__'
I get something like this:
{
"id": 62,
"sender": {
"pk": 12,
"email": "john#gmail.com",
"full_name": "John",
"profile_photo": null
},
"created_at": "2018-04-29T00:54:50.437662",
"message": "sdkjnasljdhkajsjdlasdasda",
"read_at": false,
"target": 18
}
I would like the target field to be like sender, that is: display the full user information instead of just the ID.
I tried to add this line: target = UserMobileSerializer(), but I still get only the ID in the output. I also tried target = UserMobileSerializer(read_only=True) but nothing changed.
You are not adding the field you defined to the fields in the serializer's Meta. Try this:
class MessageSerializer(ModelSerializer):
sender = UserMobileSerializer(read_only=True)
class Meta:
model = Messages
fields = ('your', 'fields', 'sender')
EDIT: You need to serialize target, too. Like this:
class TargetSerializer(ModelSerializer):
class Meta:
model = Target
fields = ('id', 'title') # Add fields you want to get in the response.
class MessageSerializer(ModelSerializer):
target = TargetSerializer(read_only=True) # You should have TargetSerializer defined
sender = UserMobileSerializer(read_only=True)
class Meta:
model = Messages
fields = ('your', 'fields', 'target', 'sender')

django rest framework nested objects get or create behaviour

I am creating an api end point using django-rest-framework for a specific json input. I have two related models like so (let's assume post can only have one category):
class Category(models.Model):
name = models.CharField(max_length=10)
slug = models.SlugField()
class Post(models.Model):
category = models.ForeignKey()
title = models.CharField(max_length=100)
text = models.CharField(max_length=256)
and my serializer are simple model serializers:
class CategorySerializer(ModelSerializer):
id = serializers.IntegerField(required=True)
class Meta:
model = Category
class PostSerializer(ModelSerializer):
id = serializers.IntegerField(required=True)
category = CategorySerializer()
class Meta:
model = Post
and my api view is very simple also:
class PostAPIView(mixins.CreateModelMixin, GenericAPIView):
serializer_class = PostSerializer
permission_classes = (IsAuthenticated,)
now in order to create posts I need to parse a json input like this:
{
"id": 10,
"pk": 10
"title": "Some title",
"text": "Some text",
"category": {
"id": 15,
"pk": 15
"name": "Best category",
"slug": "best-category"
}
}
in here 'pk' parameters are crucial for me, I want data to be created on my db using exact pk provided in json. Now if I make a post request and there are no posts with id:10 and categories with id:15 all is fine and data is written to db new records get inserted, but if there are any when rest-framework returns an error like ['Post id 10 already exists'], I would like matching records to be updated according to input instead. How can I do that?
You just need to add the UpdateMixin, just import it like the CreateModelMixin.
This mixin will implement the update and partial update methods, that will do what you want.
But you can not send a POST, for it you will need a PUT, or PATCH. You you want to do this on POST, I recommend you to implement your own create view method.

How to update multiple fields which including related fields of a django model instance?

I'm wondering, what is a standard way of updating multiple fields which includes related fields of an instance of a model in django? ...
Class User(models.Model):
id = models.CharField()
name = models.CharField()
dob = models.CharField()
Class Appointment(models.Model):
user = models.ForeignKey(User)
app_id = models.CharField()
time = models.DateTimeField()
status = models.CharField()
To update multiple fields in appointment model I could just do
dict ={
"app_id": "123",
"time": "2012-01-01 10:30",
"status": "Open"
}
Appointment.objects.filter(app_id=123).update(dict)
Is there a way to update the related model?
How could I do an update on Appointment model and User Model?
Case:
dict ={
"name": "foo",
"app_id": "123",
"time": "2012-01-01 10:30",
"status": "Open"
}
For clarity's sake - that's not what 'inherited' means. Appointment is related to user, but does not inherit from it.
The update method on the queryset can't do this in a single call. The docs say:
the only restriction on the QuerySet that is updated is that it can only update columns in the model’s main table, not on related models.
https://docs.djangoproject.com/en/dev/ref/models/querysets/#update
If you have the app_id and nothing else, you can write a second update call:
User.objects.filter(appointment__app_id=123).update(name='foo')