Write operation in Reverse Relationship Django Rest Framework - django

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.

Related

How to retrieve all models data by User id in Django Serializer?

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/

Django_Rest_Framework Serializer Field "source" attribute is not working

I am trying to build a DRF Serializer that uses different names for the fields than the underlying Django Model. I thought that this is what the "source" attribute was for.
Here is some code:
models.py:
class MyModel(models.Model):
my_snake_case_field = models.DateTimeField()
serializers.py:
class MySerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = ('id', 'myCamelCaseField', )
myCamelCaseField = serializers.DateTimeField(source='my_snake_case_field')
But when I try to view that I get the following error:
ImproperlyConfigured at /api/mymodel/1/ Field name myCamelCaseField
is not valid for model MyModel.
Any ideas where I'm going wrong?
It might be a Indentation error, It should not inside the Meta class
class MySerializer(serializers.ModelSerializer):
myCamelCaseField = serializers.DateTimeField(source='my_snake_case_field')
class Meta:
model = MyModel
fields = ('id', 'myCamelCaseField',)
Try this for instance:
Now you've assigned myCamelCaseField before calling it.
class MySerializer(serializers.ModelSerializer):
myCamelCaseField = serializers.DateTimeField(source='my_snake_case_field')
class Meta:
model = MyModel
fields = ('id', 'myCamelCaseField', )

Serialization of child models

I have models:
class CommonEditor(models.Model):
def __str__(self):
return 'Common Atributes Mask'
class Color(models.Model):
name = models.CharField(max_length=25)
editor = models.ForeignKey(CommonEditor, on_delete=models.PROTECT, null=True)
So I make serialization this way:
class ColorSerializer(serializers.ModelSerializer):
class Meta:
model = Color
fields = '__all__'
class CommonAttributesSerializer(serializers.ModelSerializer):
color = ColorSerializer(many=True, read_only=True)
class Meta:
model = CommonEditor
fields = ('pk', 'color')
And then view:
class CommonAttributeAPIView(generics.ListCreateAPIView):
serializer_class = CommonAttributesSerializer
queryset = CommonEditor.objects.all()
I get only pk of my CommonEditor Model. Why can't i get the full Atributes Mask and how can I fix it? Big thanks!
Default name for reverse foreign key relation is modelname_set or in your case color_set. So try to rename color field to color_set:
class CommonAttributesSerializer(serializers.ModelSerializer):
color_set = ColorSerializer(many=True, read_only=True)
class Meta:
model = CommonEditor
fields = ('pk', 'color_set')
This can also be achieved via SerializerMethodField and can be seen as follow:
class CommonAttributesSerializer(serializers.ModelSerializer):
color = serializers.SerializerMethodField()
class Meta:
model = CommonEditor
fields = ('pk', 'color')
def get_color(self, common_editor):
return ColorSerializer(common_editor.color_set.all(), many=True).data
Documentation: http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield
The CommonAttributesSerializer search for a color attribute in CommonEditor's instance, but it couldn't find. In DRF serializer, a parameter called source will says explicitly where to look for the data. So , change the serializer as below:
class CommonAttributesSerializer(serializers.ModelSerializer):
color = ColorSerializer(many=True, read_only=True, <b>source='color_set'</b>)
class Meta:
model = CommonEditor
fields = ('pk', 'color')
Reference : DRF Fields -source

Using rest django rest framework for creating new object

I have the following models
class Peri(models.Model):
date = models.DateField()
customer = models.ForeignKey(Customer)
class PeriTask(models.Model):
#fields
peri = models.ForeignKey(Peri)
My serializers are the following
class PeriSerializer(serializers.HyperlinkedModelSerializer):
customer = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Peri
fields = ('id', 'date', 'url', 'peritasks', 'customer')
class PeriTaskSerialiazer(serializers.HyperlinkedModelSerializer):
tooth = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = PeriTask
fields = ('id', 'task_type', 'implant', 'furcation', 'bleeding1', 'bleeding2', 'bleeding3', 'plaque1', 'plaque2',
'gingival_margin1', 'gingival_margin2', 'gingival_margin3', 'probing_depth1', 'probing_depth2',
'probing_depth3', 'tooth', 'url', )
and my viewsets are
class PeriodontogrammaViewSet(ModelViewSet):
serializer_class = PeriSerializer
queryset = Peri.objects.all()
class PeriTaskViewSet(ModelViewSet):
serializer_class = PeriTaskSerialiazer
queryset = PeriTask.objects.all()
But when I try to create a new peri using the api it gives me the following integrity error
NOT NULL constraint failed: peri_peri.customer_id
My json data that beeing posted are
{"date": "2014-12-17",
"customer": 27
}
I haven't created a serializer for customer since I am not interested in having api for my other models.
In your serializer, you've set the customer key to read_only:
customer = serializers.PrimaryKeyRelatedField(read_only=True)
Try setting it to False or just simply removing this whole line (which seems superfluous to me)

django REST framework - limited queryset for nested ModelSerializer?

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', )