I am new in Django Rest APi so Please help.
I have Two models :
class Department(models.Model):
name = models.CharField(max_length = 50)
location = models.CharField(max_length=20)
dept_code = models.CharField(max_length=5)
class Employee(models.Model):
name = models.CharField(max_length = 50)
email = models.EmailField()
mobile = models.CharField(max_length=10)
department = models.ForeignKey(Department, on_delete= models.CASCADE)'
And Respective serializers are:
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = '__all__'
class DepartmentSerializer(serializers.ModelSerializer):
class Meta:
model = Department
fields = '__all__'
I want to retrieve the data in like this
{
emptId : 1,
empName : 'John',
empEmail : 'John#gmail.com',
empMobile : '1111111111',
deptId : 1,
deptName : 'Accounts',
deptLocation : 'Pune',
deptCode : 'ACC'
}
How to get the above data. Please help me
In Your Serializers.py
class DepartmentSerializer(serializers.ModelSerializer):
class Meta:
model = Department
fields = '__all__'
class EmployeeSerializer(serializers.ModelSerializer):
department = DepartmentSerializer(many=False)
class Meta:
model = Employee
fields = ('empId','empName','empEmail','empMobile','department')
using this you will get nested object structure which is preferred.
If you want to get flatten structure then
class DepartmentSerializer(serializers.ModelSerializer):
class Meta:
model = Department
fields = '__all__'
class EmployeeSerializer(serializers.ModelSerializer):
department = DepartmentSerializer(many=False)
depId = serializers.IntergerField(source='department.id')
depName = serializers.CharField(source='department.name')
depLocation = serializers.CharField(source='department.location')
depCode = serializers.CharField(source='department.dept_code')
class Meta:
model = Employee
fields = ('empId','empName','empEmail','empMobile','depId','depName','depLocation','depCode','department')
Hope you get this
If you don't want department object in get method then add write_only=True in argument of department field.
see more
readonly and writeonly
medium
You can write your serializer class like this:
class MySerializer(serializers.Serializer):
emptId = serializers.IntergerField()
empName = serializers.CharField()
empEmail = serializes.CharField()
empMobile = serializes.CharField()
depId = serializers.IntergerField()
depName = serializers.CharField()
depLocation = serializers.CharField()
depCode = serializers.CharField()
class Meta:
fields = ('emptId', 'empName', 'empEmail', 'empMobile', 'depId', 'depName', 'depLocation', 'depCode',)
And you can write your view class like this:
class MyAPIView(APIView):
def get(self, request, *args, **kwargs):
employeeId = 1
myEmployee = Employee.objects.filter(id=employeeId) \
.annotate(emptId=F('id'),
empName=F('name'),
empEmail=F('email'),
empMobile=F('mobile'),
depId=F('department__id'),
depName=F('department__name'),
depLocation=F('department__location')
depCode=F('department__dep_code').values('emptId', 'empName', 'empEmail', 'empMobile', 'depId', 'depName', 'depLocation', 'depCode').first()
mySerializer = MySerializer(myEmployee)
return Response(mySerializer, status=status.HTTP_200_OK)
I do not test the code in a real program. But you can write your code like my code. You can inspire of that.
Related
I'm now using DRF as a backend of my project.
i have product model like this
class product(models.Model):
product_name = models.CharField(max_length=160)
i have category model like this
class category(models.Model):
category_name = models.CharField(max_length=60)
category_icon = models.ImageField(upload_to='category)
because 1 product can have multiple category and a lot of image I create
class product_category(models.Model):
product = models.ForeignKey(product, on_delete=models.CASCADE, related_name='product_collections')
category = models.ForeignKey(category, on_delete=models.CASCADE, related_name='category_collections')
and the last model
class product_image(models.Model):
product = models.ForeignKey(product, on_delete=models.CASCADE,related_name='image_collections')
product_img = models.ImageField(upload_to='product')
Now I have Serializer like this
class ProductCategorySerializer(serializers.ModelSerializer):
category_name = serializers.CharField(source='category.category_name')
class Meta:
model = product_category
fields = ('product_id','category_id','category_name')
class ProductImageSerializer(serializers.ModelSerializer):
class Meta:
model = product_images
fields = ('product_img',)
class ProductSerializer(serializers.ModelSerializer):
category_collections = CategoryProductSerializers(many=True)
image_collections = ProductImageSerializer(many=True)
class Meta:
model = product
fields = ('id','product_name','image_collections','category_collections')
From that serializer DRF will return
Error like this
Got AttributeError when attempting to get a value for field category_collections on serializer ProductSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the product instance.
but if i remove that category_collections field like this
class ProductSerializer(serializers.ModelSerializer):
# category_collections = CategoryProductSerializers(many=True)
image_collections = ProductImageSerializer(many=True)
class Meta:
model = product
fields = ('id','product_name','image_collections')
Everything is going fine, whats wrong with that categories collection, is my eye not seeing the mistake ?
I have two models in a 'many to many' relationship Video and Genre. I want to represent them in my API using the Django Rest Framework and with Hyperlinking. I have tried using the the nested relationships solution that I have found over the internet but it brings me an error for the list viewss eg genres/ and videos/ as described below.
models.py
class VideoGenre(models.Model):
video = models.ForeignKey(Video, on_delete=models.CASCADE, related_name='genres')
genres = models.ForeignKey(Genre, on_delete=models.CASCADE, related_name='videos')
class Meta:
unique_together = ['video', 'genre']
class Video(models.Model):
genres = models.ManyToManyField(Genre, related_name="videos", blank=True, through='VideoGenre')
title = serializers.CharField(default=serializers.CurrentUserDefault())
class Genre(models.Model):
name = models.CharField(max_length=20)
descr = models.CharField(max_length=255)
serializers.py
class GenreSerializer(serializers.HyperlinkedModelSerializer):
videos = serializers.HyperlinkedIdentityField(many=True, view_name="video-detail")
class Meta:
model = ku_api_models.Genre
fields = "__all__"
class VideoSerializer(serializers.HyperlinkedModelSerializer):
genres = GenreSerializer(source='genre_set', many=True, read_only=True)
class Meta:
model = ku_api_models.Video
fields = "__all__"
class VideoGenreSerializer(serializers.HyperlinkedModelSerializer):
video = serializers.ReadOnlyField(source='video.id')
genre = serializers.ReadOnlyField(source='genre.id')
class Meta:
model = ku_api_models.VideoGenre
fields = "__all__"
unique_together = ['video', 'genre']
views.py
class VideoDetailView(RetrieveUpdateDestroyAPIView):
parser_classes = (MultiPartParser,)
serializer_class = VideoSerializer
queryset = Video.objects.all()
def perform_update(self, serializer):
serializer.save(owner=self.request.user)
class VideoListView(ListCreateAPIView):
parser_classes = (MultiPartParser,)
serializer_class = VideoSerializer
queryset = Video.objects.all()
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class GenreListView(ListCreateAPIView):
serializer_class = GenreSerializer
queryset = Genre.objects.all()
class GenreDetailtView(RetrieveUpdateDestroyAPIView):
serializer_class = GenreSerializer
queryset = Genre.objects.all()
urls.py
path('videos/', views.VideoListView.as_view(), name='video-list'),
path('videos/<int:pk>', views.VideoDetailView.as_view(), name='video-detail'),
path('genres/', views.GenreListView.as_view(), name="genre-list"),
path('genres/<int:pk>', views.GenreDetailtView.as_view(), name="genre-detail"),
I am getting below exception on the browsable API renderer
Exception Type: ProgrammingError at /api/genres/
Exception Value: relation "ku_api_videogenre" does not exist
LINE 1: ..._video"."owner_id" FROM "ku_api_video" INNER JOIN "ku_api_vi...
I have looked into these below links as referred above
django rest framework serializing many to many field
many to many relationship through an intermidiate model
serializing many to many field
... and tried them but getting the same/almost the same, only different is the relation name that "does not exist"
What am I missing? How to make it right? Thanks
I have found a way to this:
Changes will be in the serializers.py
serializers.py
class VideoSerializer(serializers.HyperlinkedModelSerializer):
genres = serializers.HyperlinkedRelatedField(many=True, read_only=False, view_name='genre-detail', queryset=ku_api_models.Genre.objects.all())
class Meta:
model = ku_api_models.Video
#fields = ('url', 'id', 'datetime_added', 'title', 'video_file', 'owner')
fields = "__all__"
def create(self, validated_data):
genres = validated_data.pop('genres', [])
video_instance = ku_api_models.Video.objects.create(**validated_data)
video_instance.genres.set(genres)
return video_instance
def update(self, instance, validated_data):
genres = validated_data.pop('genres', [])
instance.genres.set(genres)
instance.save()
return instance
class VideoGenreSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ku_api_models.VideoGenre
fields = "__all__"
class GenreSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = ku_api_models.Genre
fields = "__all__"
Source: Docs: intermediary-manytomany
It may be a challenging question if you didn't get rightly. Here I have three models in which department model should be created by taking its place name from Place model which is related to the staff model. The Staff Model is in a OneToOneField relationship with User, so when a user creates a department the place name should be passed like HiddenField in HTML . This place name is related to place model with the user with GenericForeignKey. i have created a serializer which is not working as expected, it is returning the place name ,
.
In shortly I want to create a department while place should be selected from current user ID
class Staff(BaseModel):
ROLES = [
('ADMIN', 'Admin'),
('TEACHER', 'Teacher')
]
auth_user = models.OneToOneField(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
school_content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
school_id = models.PositiveIntegerField()
school = GenericForeignKey('school_content_type', 'school_id')
role = models.CharField(null=True, blank=True, choices=ROLES, max_length=20)
class Places(BaseModel):
name = models.CharField(max_length=50)
code = models.CharField(max_length=12, unique=True)
class Department(BaseModel):
TYPES = [
('ONLINE', 'Online'),
('OFFLINE', 'OfFline')
]
department_type = models.CharField(max_length=15, choices=TYPES)
service_no = models.CharField(max_length=50)
instructions = models.TextField(null=True, blank=True)
place = models.ForeignKey(Places, to_field='code', db_column='place_code', on_delete=models.PROTECT)
SERIALIZERS
class DepartmentCreateSerializer(serializers.ModelSerializer):
place_code=serializers.CharField(read_only=True)
class Meta:
model=Department
fields = ('department_type','service_no','instructions')
def get_place(self, request):
user_id=self.context['request'].user.id
school_id=Staff.objects.get(auth_user_id= user_id).school_id
places_code_name=Places.objects.get(id= school_id).name
class PlacesSerializer(serializers.ModelSerializer):
class Meta:
model = Places
fields = ('id', 'code', 'name')
from places.serializers import PlacesSerializer
class DepartmentCreateSerializer(serializers.ModelSerializer):
place= PlacesSerializer(read_only=True)
class Meta:
model=Department
fields = ('place','service_no','instructions')
def validate(self, attrs):
palce_obj = self.context['request'].user.staff.place()
attrs.update({'place': place_obj})
attrs = super().validate(attrs)
if not attrs.get('place', None):
raise serializers.ValidationError({'place': ["Place required"]})
return attrs
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.
I have the following model and serializer:
class SeminarTracking(models.Model):
id = models.BigIntegerField(primary_key=True)
id_tax_seminar = models.BigIntegerField(null=True, blank=True)
cid = models.ForeignKey('clients.Client')
invite = models.IntegerField(null=True, blank=True)
invite_2 = models.IntegerField(null=True, blank=True)
rsvp = models.CharField(max_length=255L, blank=True)
attendees = models.IntegerField(null=True, blank=True)
names = models.CharField(max_length=255L, blank=True)
notes = models.TextField(blank=True)
class Meta:
db_table = 'tax_seminars_tracking'
class SeminarTrackingSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = SeminarTracking
Client serialize:
class ClientSerializer(serializers.HyperlinkedModelSerializer):
#adwebsite = serializers.PrimaryKeyRelatedField()
#adissue = serializers.PrimaryKeyRelatedField(required=False)
#category = serializers.PrimaryKeyRelatedField(many=True)
status = serializers.Field()
seminars = SeminarTrackingSerializer(source='seminartracking_set')
class Meta:
model = Client
Whenever I access the client via the API, I get the following error:
(1054, "Unknown column 'tax_seminars_tracking.cid_id' in 'field list'")
If I access seminartracking_set in a view or template, it works no problems. Is there something I am missing? - Note the primary key of the client model is clientid, not id - not sure if that's relevant.
Many thanks, Ben
I had to specify the column name on the "cid" feild.