I have following serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id']
class PersonSerializer(serializers.ModelSerializer):
user = UserSerializer()
comments = CommentSerializer(source='comment_set', many=True)
class Meta:
model = Person
fields = '__all__'
And related views
class PersonRetrieveView(generics.RetrieveAPIView):
queryset = Person.objects.all()
serializer_class = PersonSerializer
class UserRetrieveView(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = (permissions.IsAuthenticated, )
The models are standard, Person related to User by Foreign key.
So my url path('persons/<int:pk>/', PersonRetrieveView.as_view()), returns Person object with user field with user id. I want to make kinda reverse logic. By user id I want to query all users with field person with all persons related to this user by user id.
I can't just make
class UserSerializer(serializers.ModelSerializer):
person = PersonSerializer()
class Meta:
model = User
fields = ['id']
because Person serializer defined below the User serializer. Is there any way to do it simple with generics?
Your models.py should look like this:
class Person(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
related_name='persons', # This is important
on_delete=models.CASCADE
)
# Other fields...
Then serializers.py:
class PersonSerializer(serializers.ModelSerializer):
persons=serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Person
For more info or other relation types you can look at the DRF doc:
https://www.django-rest-framework.org/api-guide/relations/
Related
my model
class Vacatures(models.Model):
title = models.CharField(max_length=50)
employer = models.ForeignKey(Employer, on_delete=models.CASCADE)
my .view
class VacaturesOverzichtMobile(generics.ListAPIView):
model = Vacatures
serializer_class = VacaturesSerializer
queryset = Vacatures.objects.all()
def get_queryset(self):
queryset = Vacatures.objects.all()
return queryset
So in the model there is Employer as foreign key. The api call in the view is working fine. The only thing is I get the employer as employer.pk , but I want the name of the Employer which is in the Employers model.
Can I tune the queryset so that it returns employer.name instead of employer.pk
I'd probably go with serializers for both models of the relationship as described in the DRF documentation. Then you have full control over which attributes of Employer you want to include. This approach is called "serializers as fields" in DRF.
class EmployerSerializer(serializers.ModelSerializer):
class Meta:
model = Employer
fields = ['name']
class VacaturesSerializer(serializers.ModelSerializer):
employer = EmployerSerializer(read_only=True)
class Meta:
model = Vacatures
fields = ['title']
I am using the Django REST Framework and I have a serializer as follows:
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
depth = 1
fields = ['user','team','correct','wrong','percentage']
The problem if this passes all user data (including a hashed password). How do I limit the fields being passed?
I have a UserSerializer as follows (which holds the only fields I really want):
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['first_name','last_name','username']
Instead of depth option declare user field explicitly in UserProfileSerializer and use UserSerializer for this field:
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = UserProfile
fields = ['user','team','correct','wrong','percentage']
Or try to override build_nested_field like this:
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
depth = 1
fields = ['user','team','correct','wrong','percentage']
def build_nested_field(self, field_name, relation_info, nested_depth):
if field_name == 'user':
field_class = UserSerializer
field_kwargs = get_nested_relation_kwargs(relation_info)
return field_class, field_kwargs
return super().build_nested_field(field_name, relation_info, nested_depth)
i am very new to django , and started writing serializers and come with this issue
i have extended my user class from user_profile class
now i want to write the user_profile serializer to save data in user Profile and user
this is my user serializer
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email','password','is_staff')
it working fine
this is my user_profile class
class User_Profile(models.Model):
class Meta:
db_table = 'user_profile'
user = models.OneToOneField(User, on_delete=models.CASCADE)
phoneNumber = models.CharField(max_length=10)
now i write this serializer for user profile
class UserProfileSerializer(serializers.HyperlinkedModelSerializer):
email = serializers.CharField(source='user.email')
username = serializers.CharField(source='user.username')
class Meta:
model = User_Profile
fields = ('url', 'phoneNumber','email','username')
but it does save the user and user profile data , and it gives error like this
Cannot assign "{u'username': u'test12', u'email': u'test#12.cm'}": "User_Profile.user" must be a "User" instance.
Please help!
I have models like this:
class Car(models.Model):
name = models.CharField(max_length=255)
class CarImage(models.Model):
car = models.ForeignKey(Car, related_name='photos')
photo = models.ImageField(upload_to='car/')
For the serializer I have:
class CarImageSerializer(serializer.ModelSerializer):
class Meta:
model = CarImage
class CarSerializer(serializer.ModelSerializer):
photos = CarImageSerializer()
class Meta:
model = Car
fields = ('id', 'name', 'photos',)
When the web interface for CarSerializer loads I get non_field_errors on the photos field by default. Is this kind of thing supported by DRF? If not what's the best way to do this?
P.S I am using generic CreateAPIView
Using docs you should do this from another way:
class CarSerializer(serializer.ModelSerializer):
photos = serializers.RelatedField(many=True)
class Meta:
model = Car
fields = ('id', 'name', 'photos',)
Maybe you can try this:
serializers.py
class CarImageSerializer(serializers.ModelSerializer):
class Meta:
model = CarImage
class CarSerializer(serializers.HyperlinkedModelSerializer):
photos = serializers.HyperlinkedRelatedField(many=True,
view_name='carimage-list')
class Meta:
model = Car
fields = ('id', 'name', 'photos',)
views.py
class CarImageList(ListCreateAPIView):
queryset = CarImage.objects.all()
serializer_class = CarImageSerializer
class CarList(ListCreateAPIView):
queryset = Car.objects.all()
serializer_class = CarSerializer
urls.py
url(r'^carimage/$', CarImageList.as_view(), name='carimage-list'),
url(r'^car/$', CarList.as_view(), name='car-list'),
You should take care about all needed imports. No guarantee, but you could give it a try.
I have a ModelSerializer, but by default it serializes all the objects in my model. I would like to limit this queryset to only the most recent 500 (as opposed to all 50 million). How do I do this?
What I have currently is the following:
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
The reason I don't think I can just specify the queryset in my viewset is that this is in fact the nested portion of another serializer.
models.py
class Container(models.Model):
size = models.CharField(max_length=20)
shape = models.CharField(max_length=20)
class Item(models.Model):
container = models.ForeignKey(Container, related_name='items')
name = models.CharField(max_length=20)
color = models.CharField(max_length=20)
views.py
class ContainerViewSet(viewsets.ModelViewSet):
queryset = Container.objects.all() # only a handful of containers
serializer_class = ContainerSerializer
serializers.py
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('name', 'color')
class ContainerSerializer(serializers.ModelSerializer):
items = ItemSerializer(many=True) # millions of items per container
class Meta:
model = Container
fields = ('size', 'shape', 'items')
In your View Set you may specify the queryset like follows:
from rest_framework import serializers, viewsets
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
class MyModelViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()[:500]
serializer_class = MyModelSerializer
I think what you are looking for is the SerializerMethodField.
So your code would look as follows:
class ContainerSerializer(serializers.ModelSerializer):
items = SerializerMethodField('get_items')
class Meta:
model = Container
fields = ('size', 'shape', 'items')
def get_items(self, container):
items = Item.objects.filter(container=container)[:500] # Whatever your query may be
serializer = ItemSerializer(instance=items, many=True)
return serializer.data
The one catch is that the SerializerMethodField is read only.
You may use source parameter
class Container(models.Model):
...
def get_items(self):
return self.items[:500]
and in serializer
items = ItemSerializer(many=True, source='get_items', )