Adding field from joined model in Django rest - python

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

Related

Contacts matching query does not exist in django rest framework

I am trying to update Contact model fields while creating the new fields of UpdateInfo model and add them to the existing model.
But I am getting this error
contacts.models.Contacts.DoesNotExist: Contacts matching query does not exist.
I know the contact object with the id 19 exists because I can see it when I try the get contacts API.
I am sending data like this.
My models:
class Contacts(models.Model):
full_name = models.CharField(max_length=100, blank=True)
.........
def __str__(self):
return self.full_name
class Meta:
verbose_name_plural = 'Potential Clients'
class UpdateInfo(models.Model):
contacts = models.ForeignKey(Contacts,on_delete=models.CASCADE, related_name='update_info')
updated_at = models.DateTimeField(auto_now=True)
modified_by = models.CharField(max_length=100, blank=True)
def __str__(self):
return f"Last modified by {self.modified_by} at {self.updated_at}"
My views:
class EditContactView(RetrieveUpdateDestroyAPIView):
permission_classes = [IsAuthenticated]
queryset = Contacts.objects.all()
serializer_class = ContactsUpdateSeializer
My serializers:
class UpdateInfoSerializer(serializers.ModelSerializer):
contacts= serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = UpdateInfo
fields = ['id','contacts','updated_at','modified_by']
class ContactsUpdateSeializer(serializers.ModelSerializer):
update_info = UpdateInfoSerializer(many=True)
id = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Contacts
fields = ['id', 'full_name', 'lead_source', 'email', 'phone', 'contact_owner',
'contact_status', 'company_name', 'job_position', 'tasks',
'notes', 'email_list', 'created_by', 'created_at', 'update_info']
def update(self, instance, validated_data):
update_data = validated_data.pop('update_info')
id = validated_data.get('id')
contacts = Contacts.objects.get(id=id)
#contacts.save()
#contact_only_update_logic
instance.full_name = validated_data.get('full_name')
instance.lead_source = validated_data.get('lead_source')
instance.email = validated_data.get('email')
instance.phone = validated_data.get('phone')
instance.contact_owner = validated_data.get('contact_owner')
instance.contact_status = validated_data.get('contact_status')
instance.company_name = validated_data.get('company_name')
instance.job_position = validated_data.get('job_position')
instance.tasks = validated_data.get('tasks')
instance.notes = validated_data.get('notes')
instance.email_list = validated_data.get('email_list')
instance.save()
#add_update_info_logic
for update_data in update_data:
abc = UpdateInfo.objects.create(contacts=contacts,**update_data)
instance.update_info.add(abc)
instance.save()
return instance
You have to change your serializer
class ContactsUpdateSeializer(serializers.ModelSerializer):
update_info = UpdateInfoSerializer(many=True)
class Meta:
model = Contacts
fields = ['id', 'full_name', 'lead_source', 'email', 'phone', 'contact_owner',
'contact_status', 'company_name', 'job_position', 'tasks',
'notes', 'email_list', 'created_by', 'created_at', 'update_info']
def update(self, instance, validated_data):
update_data = validated_data.pop('update_info')
instance = super(ContactsUpdateSeializer, self).update(instance, validated_data)
for update_datum in update_data:
abc = UpdateInfo.objects.create(contacts=instance,**update_datum)
return instance
PrimaryKeyRelatedField is used for foreign key purpose and there we have to define queryset also.
Don't need to add the updateinfo in contact, it is already done throgh django.
Moreover, it would be better if you use bulk_create instead of running save each time if you there is no signals exists for that.
You can do it as:-
UpdateInfo.objects.bulk_create([UpdateInfo(contacts=instance,**update_datum) for update_datum in update_data])

How to update with SerializerMethodField in Django Rest Framework

I have a field in my ModelSerializer which I've set as SerializerMethodField to modify the get behaviour for the field. I could update the data before, now I can't. How can I solve this?
Initially, without using SerializerMethodField, I got data like this:
{
...
"members": [2,3],
...
}
but I added SerializerMethodField to modify the data, then update stopped working.
models.py
# Create your models here.
class Company(models.Model):
members = ArrayField(models.IntegerField(blank=True), blank=True)
...
serializers.py
class AccountSerializer(serializers.ModelSerializer):
user=serializers.StringRelatedField(read_only=False)
class Meta:
model=Account
fields='__all__'
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
class CompanySerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=False)
members = serializers.SerializerMethodField()
class Meta:
model = Company
fields = '__all__' #('id', 'name', 'description', 'date_created', 'user', 'status', 'theme', 'members')
def get_members(self, obj):
accounts = Account.objects.filter(id__in=obj.members)
return AccountSerializer(accounts, many=True).data
...
You need to use different serializers for update and create. This serializer works for get only.
Or, you can create a custom field. Django Rest Framework How to update SerializerMethodField
Or, there can be other simpler hooks. If 'create' and 'update' worked as you wanted before modifiying members, then you can do as follow to get everything to default for create and update requests.
Instead of using SerializerMethodField, override serializer representation.
class CompanySerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=False)
class Meta:
model = Company
fields = ('id', 'name', 'description', 'date_created', 'user', 'status', 'theme', 'members', 'members_data')
def to_representation(self, obj)
ret = super().to_representation(obj)
ret["members"] = AccountSerializer(accounts, many=True).data
return ret
Override the __init__ method .
.
class CompanySerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
try:
if self.context['request'].method in ['GET']:
self.fields['members'] = SerializerMethodField()
except KeyError:
pass
class Meta:
model = Company
fields = '__all__' #('id', 'name', 'description', 'date_created', 'user', 'status', 'theme', 'members')
def get_members(self, obj):
accounts = Account.objects.filter(id__in=obj.members)
return AccountSerializer(accounts, many=True).data
...
Or, you can create different field for getting members.
class CompanySerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=False)
members_data = SerializerMethodField()
class Meta:
model = Company
fields = ('id', 'name', 'description', 'date_created', 'user', 'status', 'theme', 'members', 'members_data')
def get_members_data(self, obj):
accounts = Account.objects.filter(id__in=obj.members)
return AccountSerializer(accounts, many=True).data
...

How to serialize result of objects.filter django based on foreign key object

I have two models one with a foreign key to the other:
class Booking(models.Model):
type_course_requested = models.ManyToManyField(TypePost, blank=True)
.....
#Presentation Message
message = models.CharField(max_length=1000)
class BookingDemand(models.Model):
booking = models.ForeignKey(Booking, on_delete=models.CASCADE, null=True, blank=True)
I want to get bookingdemands based on certain condition, and then serializing to have something like the code below:
{ 'booking1': { 'key1':...
'bookingDemands': {....}
},
'booking2': {...}
}
Filtering is done like this:
bookings=BookingDemand.objects.filter(booking__post__person=self.request.user)
which returns a queryset, but I can't find how to serialize them to have each booking separatly as mentionned above.
Create a serializer and set depth=1 as below
from rest_framework import serializers
class BookingDemandSerializer(serializers.ModelSerializer):
class Meta:
model = BookingDemand
fields = '__all__'
depth = 1
then serialize your queryset as
bookings = BookingDemand.objects.filter(booking__post__person=self.request.user)
booking_serializer = BookingDemandSerializer(bookings, many=True)
booking_serializer.data # here is the serialized data
UPDATE
# serializer.py
from rest_framework import serializers
class BookingDemandSerializer(serializers.ModelSerializer):
class Meta:
model = BookingDemand
fields = '__all__'
class BookingSerializer(serializers.ModelSerializer):
booking_demands = BookingDemandSerializer(source='bookingdemand_set', many=True)
class Meta:
model = Booking
fields = '__all__'
# serialization process
queryset = Booking.objects.all() # apply filter if you want
serializer = BookingSerializer(queryset, many=True)
serializer.data # here is the data
Create two serializers BookingSerializer and BookingDemandSerializer and add
booking(related_name) = BookingDemandSerializer(many=True) in BookingSerializer

Django Rest Framework Serializer Doesn't Display ALL Fields

I have a problem where DRF isn't displaying all of my fields correctly for a model class / reference table (specifically the primary key).
My Model Class looks like this (very simple):
class UnitOfIssue(models.Model):
code = models.CharField(max_length=2, primary_key=True)
description = models.CharField(max_length=16)
class Meta:
ordering = ('code',)
def __str__(self):
return "{0} - {1}".format(self.code, self.description)
My Serializer Looks like this:
class UnitOfIssueSerializer(serializers.HyperlinkedModelSerializer):
"""
"""
url = serializers.HyperlinkedIdentityField(
read_only=True,
view_name='unitofissue-detail',
format='html',
lookup_field='code')
class Meta:
model = UnitOfIssue
fields = ('code', 'description', 'url')
# fields = '__all__'
And I'm using a generic view:
class UnitOfIssueDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = UnitOfIssue.objects.all()
serializer_class = UnitOfIssueSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
lookup_field = 'code'
In order for the UnitOfIssue primary key code to be displayed in the auto-generated UI, I have to define fields = ('code', 'description', 'url') in the serializer instead of fields = '__all__'.
I want to just be able to use the '__all__' syntax but I can't figure out what's going wrong.
Also, I'm using Django==1.11.13 and djangorestframework==3.8.2
This issue plagued me for weeks, and yet it was such a simple error. I fixed it by changing the serializer base class from:
class UnitOfIssueSerializer(serializers.HyperlinkedModelSerializer):
to:
class UnitOfIssueSerializer(serializers.ModelSerializer):

django rest framework posting object with relations fails to create

I cannot make the Django rest framework to create the object with dependency. In short here is the simplified configuration that works for other part update, remove and create Employee. But it fails when creating Case with ForeignKey to Employee.
models.py
class Employee(models.Model):
firstName = models.CharField(max_length=50)
lastName = models.CharField(max_length=50)
class Case(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Employee, related_name='cases_created')
serializers.py
class SCase (serializers.HyperlinkedModelSerializer):
author = SEmployeeList(required = True)
class Meta:
model = models.Case
fields = ('url', 'title', 'author', 'id')
class SEmployee(serializers.HyperlinkedModelSerializer):
cases_created = SCaseList(many=True, required=False)
class Meta:
model = models.Employee
fields = ('url', 'firstName', 'lastName','cases_created', 'id')
views.py
class EmployeeViewSet(viewsets.ModelViewSet):
queryset = models.Employee.objects.all()
serializer_class = serializers.SEmployee
class CaseViewSet(viewsets.ModelViewSet):
queryset = models.Case.objects.all()
serializer_class = serializers.SCase
The issue is when I create the object case, that must have reference to author.
Passing existing objects creates the Case and new employee
POST
{"author":{"url":"http://localhost:8000/restbase/employee/23/",
"firstName":"Mark",
"lastName":"Hilton",
"cases_created":[],
"id":23},
"title":"New Case"
}
Passing only URL for and existing author fails because creating author fails.
POST
{"author":"http://127.0.0.1:8000/restbase/employee/23/","title":"New Case"}
RESPONSE
{"author": [{"non_field_errors": ["Invalid data"]}]}
Passing only URL as an field of author brings following resposne
POST
{"author":{"url":"http://127.0.0.1:8000/restbase/employee/23/"},"title":"New Case"}
RESPONSE
{"author": [{"lastName": ["This field is required."], "firstName": ["This field is required."]}]}
After the investigation deeper there is a working solution. The author cannot be serialized.
class SCase (serializers.HyperlinkedModelSerializer):
# removed line: author = SEmployeeList(required = True)
class Meta:
model = models.Case
fields = ('url', 'title', 'author', 'id')
I still do not know how to use detailed information and create depended element

Categories