Django Rest Framework User Model Serializer Nested - python

I am having some issues with my DRF Serializers. I essentially have a model that has Django users as Foreign keys so I can see who is attached to a job.
When I try and resolve these user ID's nested inside my Job serializer using a User serializer I only see the ID, but when I use the User serializer on it's own not nested I get the correct fields returned. Below is my code snippets. Any help would be great.
models.py
from profiles.models import UserProfile
class Job(models.Model):
name = models.CharField(max_length=256, blank=False)
designer_one = models.ForeignKey(UserProfile, related_name='designer_one', on_delete=models.DO_NOTHING)
designer_two = models.ForeignKey(UserProfile, related_name='designer_two', on_delete=models.DO_NOTHING)
def __str__(self):
return self.name
class Meta(object):
verbose_name = "Job"
verbose_name_plural = "Jobs"
ordering = ['name']
serializers.py
from django.contrib.auth.models import User
class UsersSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'email', 'first_name', 'last_name')
class JobsSerializer(serializers.ModelSerializer):
tasks = TasksSerializer(many=True, read_only=True)
designer_one = UsersSerializer(many=False, read_only=True)
designer_two = UsersSerializer(many=False, read_only=True)
class Meta:
model = Job
fields = ('id', 'name', 'designer_one', 'designer_two', 'tasks')
What I get returned from UsersSerializer API View
[
{
"id": 1,
"email": "test#example.co.uk",
"first_name": "Admin",
"last_name": "User"
},
{
"id": 2,
"email": "test1#example.co.uk",
"first_name": "",
"last_name": ""
}
]
What I get returned from JobsSerializer API View
{
"id": 1,
"name": "Test job",
"designer_one": {
"id": 1
},
"designer_two": {
"id": 1
},
"tasks": [
{
"id": 1,
"name": "Test Task",
"job": 1
}
]
}

The issue is that you are using UsersSerializer for model User, meanwhile designer_one and designer_two are of type UserProfiile.
You can allow DRF generate the nested serializers for you using the depth option as #Anup Yadav suggested but if you want to have control over which fields are displayed, you need to create your own serializer for Userprofile and use it in the Job serializer

Related

Django REST Framework group by in nested model

I'm new to Django REST Framework.
I have a nested model for saving orders of a restaurant. When I send a GET request I get the following response:
[
{
"menu": {
"id": 1,
"food_name": "food1"
},
"user": {
"id": 49,
"username": "A"
}
},
{
"menu": {
"id": 1,
"food_name": "food1"
},
"user": {
"id": 63,
"username": "B"
}
}
]
But I want to group users with the same menu like this:
[
{
"menu": {
"id": 1,
"food_name": "food1",
"users": {
"1": {
"id": 49,
"username": "A"
},
"2": {
"id": 63,
"username": "B"
}
}
}
}
]
Here is my code:
models.py
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
menu = models.ForeignKey(Menu, on_delete=models.CASCADE)
views.py
class OrderViewSet(viewsets.ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
serilizers.py
class OrderSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
menu = MenuSerializer()
class Meta:
model = Order
fields = ['id', 'user', 'menu']
Thanks
Since your output suggests that you are working with menus, I suggest you create a separate viewset that works with menus and returns the expected output you want here.
Doing the expected results in the order viewset is possible, but is tricky to optimise using select_related and prefetch_related. But if you really want this in your order viewset, then you can do this with:
class MenuSerializer(serializers.ModelSerializer):
users = serializers.SerializerMethodField()
class Meta:
model = Menu
fields = ['id', 'food_name', 'users']
def get_users(self, obj):
users = User.objects.filter(pk__in=obj.order_set.all().values('user'))
return UserSerializer(users, many=True).data
class OrderSerializer(serializers.HyperlinkedModelSerializer):
menu = MenuSerializer()
class Meta:
model = Order
fields = ['id', 'menu']
You also need to change the queryset of the view if you want distinct results, otherwise you will get duplicates:
class OrderViewSet(viewsets.ModelViewSet):
queryset = Order.objects.all().distinct('menu')
serializer_class = OrderSerializer
Do note that this is not optimised, and each row in your order table will require hitting the database just to get the users through menu. distinct('menu') also only works on PostgreSQL.
You can nest User into Menu if you want to group by menu
class OrderSerializer(serializers.HyperlinkedModelSerializer):
menu = MenuSerializer(many=True)
class Meta:
model = Order
fields = ['id', 'menu']
class MenuSerializer(serializers.ModelSerializer):
user = UserSerializer(many=True)
class Meta:
model = Menu
fields = ['id', 'user']

How to select the fields that i want to show in DRF using a foreign key

I'm working on a small project using Django / Rest Framework, i have two models ( CustomUser and Team )
from django.db import models
from users.models import CustomUser
class Team(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
This is my serializer :
from rest_framework import serializers
from apps.teams.models import Team
class TeamSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = '__all__' # how can i show the CustomUser model fields
depth = 1
the result is :
[
{
"id": 3,
"user": {
"id": 8,
"password": "",
"last_login": null,
"is_superuser": false,
"is_staff": false,
"is_active": true,
"date_joined": "2021-05-04T21:23:46.513567Z",
"first_name": "John",
"last_name": "Doe",
"username": "testingxe",
"email": "ab#test.com",
"groups": [],
"user_permissions": []
}
}
]
how can i choose the user, fields that i want to show / i can't show all of them because i have the password ...
One way is to use nested serializers like so:
class UserSerializer(...):
class Meta:
model = User
fields = ['first_name', 'last_name', ...]
class TeamSerializer(...):
user = UserSerializer(many=False)
class Meta:
model = Team
fields = ['user', ...]

DRF, add custom field to ModelSerializer

I have some models in my project and I need a especial response of the API, i'm using Django Rest framework.
class Goal(models.Model):
name = models.CharField()
# more fields
class Task(models.Model):
name = models.CharField()
goal = models.ForeignKey(Goal)
class UserTask(models.Model):
goal = models.ForeignKey(Goal)
user = models.ForeignKey(User)
# other fields
I have this response:
{
"name": "One goal",
"task": [
{
"name": "first task"
},
{
"name": "second tas"
}
]
}
But I need this:
{
"name": "One goal",
"task": [
{
"name": "first task",
"is_in_usertask": true
},
{
"name": "second tas",
"is_in_usertask": false
}
]
}
I saw this in DRF docs but I don't know how to filter UserTask by the current user (or other that is given in URL paramenter) and each Goal.
Edit:
# serializers
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
class GoalSerializer(serializers.ModelSerializer):
# related_name works fine
tasks = TaskSerializer(many=True)
class Meta:
model = Goal
try to use SerializerMethodField field as
class TaskSerializer(serializers.ModelSerializer):
is_in_usertask = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Task
fields = ('name', 'is_in_usertask')
def get_is_in_usertask(self, task):
return UserTask.objects.filter(user=self.context['request'].user, goal=task.goal).exists()
Take a look to this conversation: How to get Request.User in Django-Rest-Framework serializer?
You can't access to request.user directly

Django RestframeWork Serializer relations , How to get the data of both of One to One Models?

The mode is:
class Userinfo(models.Model):
class Meta:
verbose_name='用户信息'
verbose_name_plural='用户信息'
user=models.OneToOneField(
User,
related_name='userinfo',
on_delete=models.CASCADE,
verbose_name='用户'
)
location=models.BooleanField(verbose_name='地点(勾选宏达,否则福年)')
And the Restframework Token class:
#python_2_unicode_compatible
class Token(models.Model):
"""
The default authorization token model.
"""
key = models.CharField(_("Key"), max_length=40, primary_key=True)
user = models.OneToOneField(
settings.AUTH_USER_MODEL, related_name='auth_token',
on_delete=models.CASCADE, verbose_name=_("User")
)
created = models.DateTimeField(_("Created"), auto_now_add=True)
My serializers is:
class UserinfoSerializer(serializers.ModelSerializer):
class Meta:
model=Userinfo
fields="__all__"
class UserSerializer(serializers.ModelSerializer):
class Meta:
model=User
exclude=('password',)
userinfo=UserinfoSerializer()
class TokenSerializer(serializers.ModelSerializer):
class Meta:
model=Token
fields = '__all__'
depth=3
user = UserSerializer()
I want to Response the data of User and the One to One Model Userinfo,but I just get the user. what can I to?
Here is my current result of Token serializer data,and The userinfo is null, How can I get the userinfo data?
{
"key": "2012964fb4ffe07dc58c33a64d0ce48bedd34643",
"user": {
"id": 3,
"userinfo": null,
"last_login": null,
"is_superuser": false,
"username": "333",
"first_name": "叶同学",
"last_name": "",
"email": "",
"is_staff": false,
"is_active": true,
"date_joined": "2017-12-08T16:39:00+08:00",
"groups": [],
"user_permissions": []
},
"created": "2017-12-14T10:40:58.933072+08:00"
}
Add in class meta of UserSerializer
depth = 1
OR
use UserinfoSerializer for
userinfo = UserinfoSerializer(source="userinfo")
like
class UserSerializer(serializers.ModelSerializer):
userinfo = UserinfoSerializer(source="userinfo")
class Meta:
depth = 2
model=User
**fields = ('userinfo')** # You missed this that's why you used depth but it was not working for you. Please replicate same in TokenSerializer
Please see below my edit
class TokenSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model=Token
fields = ('__all__','user')
depth=3
May be instead of all, you need to mention fields which are required.

Retrieve nested dict from Django nested queryset with ForeignKey?

I have a models.py having:
class Other(models.Model):
name = models.CharField(max_length=200)
class ModelA(models.Model):
name = models.CharField(max_length=200)
other = models.ForeignKey(Other, on_delete=models.PROTECT)
in my rest API i want to retrieve as JsonResponse a json like this:
{
"modelA": {
"id": "modelA id automatically assigned by django model",
"name": "my modelA name",
"other": {
"id": "other thing id also automatically assigned by django model",
"name": "other thing name"
}
}
}
What is the most "pythonic" way to do it?
What you are looking for is nested serialization.
In your serializers.py you should use the serializer for the Other model inside the one for your ModelA.
In serializers.py:
from rest_framework import serializers
from .models import Other, ModelA
class OtherSerializer(serializers.ModelSerializer):
class Meta:
model = Other
fields = ('id', 'name')
class ModelASerializer(serializers.ModelSerializer):
other = OtherSerializer(read_only=True)
# The magic happens here.
# You use your already created OtherSerializer inside the one for ModelA
# And that will perform nested serialization
# Which will produce the result that you want
class Meta:
model = ModelA
fields = ('id', 'name', 'other')
# _________________________^
And now you get result like:
{
"id": 1,
"name": "my modelA name",
"other": {
"id": 1,
"name": "other thing name"
}
}

Categories

Resources