I'm trying to pull the permissions data into my UserSerializer. I have a Many To Many relationship with User to Group with a through table called GroupUser. I'm able to pull the group_id and the group_name, but I can't seem to populate the data for permissions into my User Serializer.
So far I've tried using permission = serializers.ReadOnlyField(source='group.permissions') but that doesn't work.
Any suggestions?
Here's my code:
class GroupSerializer(serializers.ModelSerializer):
users = GroupUserSerializer(source='groupuser_set', many=True)
permissions = PermissionSerializer(source='permission_set', many=True)
class Meta:
model = Group
fields = ('id', 'name', 'users', 'permissions', 'role', )
class GroupUserSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField(source='group.id')
name = serializers.ReadOnlyField(source='group.name')
class Meta:
model = GroupUser
fields = ( 'id', 'name', )
class UserSerializer(serializers.ModelSerializer):
tests = TestSerializer(source='test_set', many=True)
groups = GroupUserSerializer(source='groupuser_set', many=True)
class Meta:
model = User
fields = ( 'id', 'username', 'groups', 'tests', )
I want my data to look like this:
{
"id": 1,
"username": "user",
"groups": [
{
"id": 2,
"name": "employee"
"permission": "Access-Denied"
}
],
"tests": []
},
but I have it without "permissions"
class UserSerializer(serializers.ModelSerializer):
tests = TestSerializer(source='test_set', many=True)
groups = GroupSerializer(read_only=True, many=True)
class Meta:
model = User
fields = ( 'id', 'username', 'groups', 'tests', )
Edited explanation:
I was able to find the answer with a little tinkering.
I thought, from reading docs and stackoverflow questions, you had to include the 'Through' table when referencing a many to many relationship, but that's not true, the serializer already does it for you.
So I added the groups, as shown, with that information and all the data that is associated in the GroupSerializer with a relationship with data was populated just like the way I want it to be.
I recommend you to write a new Serializer for your UserSerializer, this will not affect other Serializers:
class GroupForUserSerializer(serializers.ModelSerializer):
users = GroupUserSerializer(source='groupuser_set', many=True)
permissions = PermissionSerializer(read_only=True , many=True)
class Meta:
model = Group
fields = ('id', 'name', 'permissions' )
Then you can in your UserSerializer use GroupForUserSerializer now:
class UserSerializer(serializers.ModelSerializer):
tests = TestSerializer(source='test_set', many=True)
groups = GroupForUserSerializer(source='groupuser_set', many=True)
class Meta:
model = User
fields = ( 'id', 'username', 'groups', 'tests' )
Related
my serializer.py file is as
...
class RelativeSerializerSLC(serializers.ModelSerializer):
full_name = serializers.CharField(source="user.full_name")
rtl_full_name = serializers.CharField(source="user.rtl_full_name")
gender = serializers.CharField(source="user.gender")
phone = serializers.CharField(source="user.phone")
email = serializers.CharField(source="user.email")
avatar = serializers.CharField(source="user.avatar")
date_of_birth = serializers.CharField(source="user.date_of_birth")
class Meta:
model = Relative
fields = ("full_name", "rtl_full_name", "gender", "phone", "email", "avatar", "date_of_birth", "blood_group", "rel")
read_only_fields = ["patient"]
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "id", "full_name", "rtl_full_name", "gender", "phone", "email", "date_of_birth", "avatar"
there i'm creating other serializer fields(userSerializer) and added to my RelativeSerializer.
that seems uglyyy to me, i have no idea on. is there any better option like using one serializer fields for other.
Thanks, new to DRF :)
Maybe try this:
class RelativeSerializerSLC(serializers.ModelSerializer):
users = UserSerializer(read_only=True)
class Meta:
model = Relative
fields = ("full_name", "rtl_full_name", "gender", "phone", "email", "avatar",
"date_of_birth", "blood_group", "rel")
read_only_fields = ["patient"]
And put UserSerializer class on top of the relativeSerializer. Let me know if it works. I don't see your model fields so it might not be.
Check out for nested serializers here https://www.django-rest-framework.org/api-guide/relations/#nested-relationships
I have got a model of User Details which is Self Related to create the relationship between two users.
Model
class AdvDetails(models.Model):
user_id = models.UUIDField(primary_key=True,default=uuid.uuid4,editable=False)
title = models.CharField(max_length=5, choices=[('Mr', 'Mr'), ('Ms', 'Ms'), ('Mrs', 'Mrs'), ('Dr', 'Dr'), ('NA', '')], default='NA')
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email_id = models.EmailField(null=True, blank=True, default=None)
parent_profile = models.ForeignKey("self", null=True, blank=True)
View Set
class AdvDetailsViewSet(viewsets.ModelViewSet):
serializer_class = AdvDetailsSerializer
filter_backends = (filters.SearchFilter,DjangoFilterBackend, filters.OrderingFilter)
filter_fields = ('email_id,'parent_profile')
search_fields = ( '^first_name',)
def get_queryset(self):
return AdvDetails.objects.all()
Serializer
class AdvDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = AdvDetails
fields = '__all__'
This structure facilitates me to help get the data in the below format
{
"user_id": "055cbde6-10ea-4558-86fc-1b42624ce760",
"title": "Mr",
"first_name": "foo",
"last_name": "bar",
"email_id" : "foo#bar.com"
"parent_profile":"6c429d4c-9fb4-42e5-9d7d-9fc782f81fb0"
}
I would like to modify the serializer in such a way that I would get the data of the parent profile's email_id as below
{
"user_id": "055cbde6-10ea-4558-86fc-1b42624ce760",
"title": "Mr",
"first_name": "foo",
"last_name": "bar",
"email_id" : "foo#bar.com",
"parent_profile":"6c429d4c-9fb4-42e5-9d7d-9fc782f81fb0",
"parent_email_id" : "parent#email.com"
}
Any help is highly appreciated. I've tried PrimaryKeyRelatedField but it was not solving my problem.
I made a package that allows expanding fields dynamically, on-demand per request:
https://github.com/rsinger86/drf-flex-fields
For your case:
class AdvDetailsSerializer(FlexFieldsModelSerializer):
class Meta:
model = AdvDetails
fields = ('user_id', 'title', 'first_name', 'last_name', 'email_id', 'parent_profile', 'parent_email_id' )
expandable_fields = {'parent_profile': '<app_name>.AdvDetailsSerializer'}
Replace <app_name> with the name of the Django app that defines the serializer, so it can be loaded lazily.
If instead you would like to statically expand a field, you can define that field as a nested serializer:
class AdvDetailsSerializer(serializers.ModelSerializer):
parent_profile = ProfileProfileSerializer()
class Meta:
model = AdvDetails
fields = (
'user_id',
'title',
'first_name',
'last_name',
'email_id',
'parent_profile',
'parent_email_id'
)
I am trying to assign current 'User' to two models using nested serializers.
class UserAddressSerializer(serializers.ModelSerializer):
class Meta:
model = UserAddress
fields = ('user', 'address_1', 'address_2', 'country',
'state_province', 'city', 'zip_code')
class UserProfileSerializer(serializers.ModelSerializer):
user_address = UserAddressSerializer()
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = UserProfile
fields = ('user', 'first_name', 'middle_name', 'last_name',
'title', 'display_name', 'time_zone', 'user_address', 'default_office')
def create(self, validated_data):
user = validated_data.pop('user')
user_address_data = validated_data.pop('user_address')
user_address_object = UserAddress.objects.create(
user=user, **user_address_data)
user_profile_object = UserProfile.objects.create(
user=user, **validated_data)
return user
What I am getting is this output in Postman.
{
"user_address": {
"user": [
"This field is required."
]
}
}
I want to know a way to pass 'User' to both of these model creation.
You need to remove user from fields of UserAddressSerializer:
class UserAddressSerializer(serializers.ModelSerializer):
class Meta:
model = UserAddress
fields = ('address_1', 'address_2', 'country', # <-- Here
'state_province', 'city', 'zip_code')
I am new to django rest framework.
I have a model Client and Project.
class Client(models.Model):
name = models.CharField(max_length=100)
class Project(models.Model):
client = models.ForeignKey(Client)
name = models.CharField(max_length=100)
in my project/serializer:
class ProjectSerializer(CoreHyperlinkedModelSerializer):
class Meta:
model = Task
fields = ('url', 'id', 'name')
in my project/views:
class ProjectViewSet(viewsets.ModelViewSet):
queryset = Project.objects.order_by('name').all()
serializer_class = ProjectSerializer
I want to be able to add the Client primary key in the ProjectSerializer so when creating in api browser view, I can be able to
add new data.
This is probably not the way you should be doing things, but to get just the primary key, you could use a PrimaryKeyRelatedField:
class ProjectSerializer(...):
client = serializers.PrimaryKeyRelatedField(queryset=Client.objects.all)
class Meta:
model = Project
fields = ('url', 'id', 'name', 'client', )
You have to add it to your Project Serializer. If you add the foreignkey to your fields, it will give you the primary key.
class ProjectSerializer(CoreHyperlinkedModelSerializer):
class Meta:
model = Task
fields = ('url', 'id', 'name', 'client', )
Or, if you want to modify your client view in Project serializer, you can use nested serialization.
class ProjectSerializer(CoreHyperlinkedModelSerializer):
client = serializers.SerializerMethodField()
def get_client(self, obj):
serializer = ClientSerializer(obj.client.objects.all())
return serializer.data
class Meta:
model = Task
fields = ('url', 'id', 'name', 'client', )
I am in little trouble while developing a web api's using Django-Rest-Framework(DRF).
Problem Statement
I have two models User and Review.
models.py
# Consider User model as `django.contrib.auth.models.User`
from django.contrib.auth.models import User
from django.db import models
# Review model
class Review(models.Model):
head = models.CharField()
content = models.CharField()
user = models.ForeignKey(User)
is_deleted = models.BooleanField(default=False)
and, i have two endpoints like this:
/users/ - list of all users
/users/<pk> - detail of user
/review/ - list of all reviews
/review/<pk> - detail of review
I want my output like this:
# /users/
[
{
"url": "http://localhost:8000/users/1",
"fisrt_name": "Adolf",
"last_name": "Hitler",
"email": "adolfhilter#xyz.com",
"is_staff": false
........ # other fields
},
.........
.........
]
# /reviews/
[
{
"url": "http://localhost:8000/reviews/1",
"head": "Head of Review",
"content": "Content of Review",
"user": {
"url": "http://localhost:8000/users/1",
"first_name": "Adolf",
"last_name": "Hitler"
},
"is_deleted": false
},
.........
.........
]
My Solution
To achieve this form of output i created three serializers class, one is UserSerializer class , second one is ReviewSerializer, and thir one id ReviewUserSerializer.These classes are as follows:
serializers.py
from rest_framework import serializers
from .models import Review
from django.contrib.auth.models import User
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'first_name', 'last_name', 'email', 'is_staff', .....)
class ReviewUserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'first_name', 'last_name')
class ReviewSerializer(serializers.HyperlinkedModelSerializer):
user = ReviewUserSerializer()
class Meta:
model = Review
fields = ('url', 'head', 'content', 'user')
So, now i want to know that ,
Is there any other way which can avoid to create an extra separate serializer class(here is ReviewUserSerializer) for these type of situations?
If yes, then suggest me a solution with proper code snippets.
Have you tried using a SerializerMethodField?
from rest_framework import serializers
from .models import Review
from django.contrib.auth.models import User
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'first_name', 'last_name', 'email', 'is_staff', .....)
class ReviewSerializer(serializers.HyperlinkedModelSerializer):
user = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Review
fields = ('url', 'head', 'content', 'user')
def get_user(self, obj) :
request = self.context['request']
return {
'url': reverse('user-detail',
kwargs={'pk': obj.user.id}, request=request),
'first_name': obj.user.first_name,
'last_name': obj.user.last_name,
}