How to use same serializer for different request? - django-rest-framework

Suppose I have a VehicleSerializer
class VehicleSerializer(serializers.Serializer):
person = PersonSerializer()
class Meta:
model = Vehicle
fields = ('id', 'type', 'person')
I need to use this serializer for get as well as post api. For get request this should be same, but for post request, i need to send data like:
{
"type": "Car",
"person": 1 (the id of the person row)
}
How can i use same Vehicle Serializer to validate this request too? As the above serializer will take only the dict value for person key.
Any help will be appreciated.

I think you need to set the person_id field for writing.
class VehicleSerializer(serializers.ModelSerializer):
person = PersonSerializer(read_only = True)
person_id = serializers.IntegerField(write_only = True)
class Meta:
model = Vehicle
fields = ('id', 'type', 'person', 'person_id')

Related

Django rest framework depth serializer only in to_representation

I have a model with many foreing keys. I want to do a POST with only ids and recieve a response with depth 1. When I set depth=1 it´s doesn´t work.
class State(models.Model):
name = models.CharField(max_length=255)
class City(models.Model):
state = models.ForeingKey(State, on_delete=models.PROTECT)
name = models.CharField(max_length=255)
class CitySerializer(serializers.ModelSerializer):
class Meta:
model = City
fields = '__all__'
I wanna post some like this
{
"state":1,
"name":"City Name"
}
And get
{
"id":1,
"name":"City Name",
"state":{
"id":1,
"name": "State Name"
}
}
Did you try to make a StateSerializer and use it in CitySerializer?
class StateSerializer(serializers.ModelSerializer):
class Meta:
model = State
fields = '__all__'
class CitySerializer(serializers.ModelSerializer):
state = StateSerializer(read_only=True)
class Meta:
model = City
fields = '__all__'
Check the doc here.

Django Rest Framework - Updating a ForeignKey Field entry in the view

In my Django Rest Framework project, I have a ForeignKey relationship between two models:
class Book(models.Model):
...
category = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True, null=True)
...
class Category(models.Model):
name = models.CharField(max_length=100, blank=False)
As you can see, a Book can belong to a Category but it does not have to. That means the 'category' field could be null.
So, in my views.py, any Book instance can be updated/patched if the user wants to assign a certain Book to a particular Category. That views.py update method looks like this:
class UpdateBooksCategory(generics.GenericAPIView):
'''
Class-based view to update the 'category' field of a Book instance.
'''
serializer_class = BookSerializer
permission_classes = [IsAuthenticated]
def patch(self, request,*args, **kwargs):
# get the Book instance first
book = Book.objects.get(pk=request.data.get('bookId'))
# if it is not assigned to a Category, then assign it
if book and not book.category:
book.category = Category.objects.get(name=request.data.get('categoryName'))
book.save()
serializer = self.get_serializer(book, context={"request": request})
return Response(serializer.data)
# otherwise, return a generic response
return Response({'response': "You have already put the selected Book in a Category."})
If you can see, first I get the Book instance that the user wants to update by using the Book's ID. If its Category field is not already filled, I get a Category instance using the given category name and assign it.
For the sake of completeness, here are my serializer classes:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name']
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ['id', /*some other fields*/,..., 'category']
So, finally my question: I wanted to know if this is the preferred way of updating a ForeingKey field like this? I mean looking at the UpdateBooksCategory class-based view, is this the right way of doing it? The code works ( I tested it with PostMan) but since I am new to DRF I wanted to know if such an updating process is correct.
You can change your BookSerializer:
class BookSerializer(serializers.ModelSerializer):
category_id = serializers.IntegerField(write_only=True)
category = CategorySerializer(read_only=True)
class Meta:
model = Book
fields = [
'id',
# some other fields,
'category',
'category_id',
]
category will be a nested data that is read only, then setting the category will be by including the category_id in your requests.

How to filter results in nested relationships in django serializer?

I am following following tutorial
https://www.django-rest-framework.org/api-guide/relations/#nested-relationships
Here is my code.
class EmpSerializer(serializers.ModelSerializer):
pass
class Meta:
model = Employee
fields = ['name', 'dept', 'start_date', 'is_full_time']
class DeptCurrEmpSerializer(serializers.ModelSerializer):
pass
currEmployees = EmpSerializer(many=True, \
queryset=Employee.objects.filter(is_full_time=True))
class Meta:
model = Department
fields = ['id']
I want to limit the DeptCurrEmpSerializer to limit the results to only the full_time employees. I get an error "unexpected keyword argument 'queryset'". Is there any other way I can do this. Eventually, the EmpSerializer itself will have an "ActiveTasks" serializer under it.

Select one to many relation table in query set django

I would like to select one to many table relation in query set.I have two model.
class Post(models.Model):
postid = models.AutoField(primary_key=True)
class Meta:
db_table = 'post'
class Images(models.Model):
postid = models.ForeignKey(Post,on_delete=models.CASCADE)
image = models.ImageField(upload_to=upload_image_to, blank=True)
In list method of Post viewset, I would like to select format like=>
{
"postid": 1,
"images":[
image:"Image Result"
]
}
Here is Post viewset =>
def list(self, request):
queryset = self.queryset
page = self.paginate_queryset(queryset)
for post in self.queryset:
img = Images.objects.all().filter(postid=post.postid)
serializer = PostSerializer(page, many=True)
return self.get_paginated_response(serializer.data)
How to insert this img result to post?
Take a look at the RelatedField documentation. Something like:
class PostSerializer(serializers.ModelSerializer):
images = serializers.StringRelatedField(many=True)
class Meta:
model = Post
fields = ['postid', 'images']
This will give you a string representation of the Image, but you can look at other Relationship fields in the documentation to customise the JSON representation of the image.
Doing it like this will likely mean you don't need to override list() in the viewset as well.

Django DRF serializer - inserting data containing foreign key relationships

I have the following models:
class Contact(models.Model):
class Meta:
managed = False
db_table = 'contact'
class ContactPhone(models.Model):
contact = models.ForeignKey(Contact, on_delete = models.CASCADE)
number = models.CharField(max_length = 45)
class Meta:
managed = False
db_table = 'contact_phone'
Also, I have the following serializers:
class ContactSerializer(serializers.ModelSerializer):
server_id = serializers.IntegerField(source='id', read_only=True)
class Meta:
model = Contact
fields = '__all__'
class ContactPhoneSerializer(serializers.ModelSerializer):
class Meta:
model = ContactPhone
fields = '__all__'
Now, I have a view that insert phone numbers for an existing contact.
The input is a json that looks like this:
data = {'contact_id': 12322,
'phones':[{'number': '89120000001'}]}
The view:
def insert_contact_phone(request):
for record in request.data['phones']:
data['contact_id'] = request.data['contact_id']
serializer = ContactPhoneSerializer(data = data)
if serializer.is_valid():
serializer.save()
I end up with the following error:
RelatedObjectDoesNotExist at /contacts/edit ContactPhone has no
contact.
What am I doing wrong?
If you specify __all__ for the fields in your ContactPhoneSerializer, it does not include contact_id.
So the contact_id taken from the json input is not serialized. It is basically ignored and when you try to save and create new ContactPhone - it fails, because it does not have contact's foreign key correctly set.
But simply adding contact_id to the serializer's fields won't solve your problem.
In your view, i recommend you to set the contact instead:
data['contact'] = request.data['contact_id']
and pass this to the ContactPhoneSerializer.

Resources