Serializing a field of the related model in a model DRF - django

I have a serializer as follows:
class ImageSerializer(serializers.HyperlinkedModelSerializer):
prop_post = serializers.SlugRelatedField(queryset=PropertyPost.objects.all(),
slug_field='pk')
class Meta:
model = Image
fields = (
'url',
'photo',
'prop_post',
)
This works Ok. Now my PropertyPost has a 'owner' field that I need to include in my ImageSerializer.
I was wondering how could I do that. I was thinking it might be like
fields = (
'url',
'photo',
'prop_post',
'prop_post__owner'
)
but it didn't work. Any help is appreciated.
here is my model:
class PropertyPost(models.Model):
owner = models.ForeignKey(
get_user_model(),
related_name='posts4thisowner',
on_delete=models.CASCADE)
class CustomUser(AbstractUser):
pass
class Image(models.Model):
prop_post = models.ForeignKey(
PropertyPost,
related_name='images4thisproperty',
on_delete=models.CASCADE)
photo = models.ImageField(upload_to=upload_update_image, null=True, blank=True)

Easier to use 'source' and you can use your user serializer to populate the owner fields.
Example:
class ImageSerializer(serializers.HyperlinkedModelSerializer):
prop_post = serializers.SlugRelatedField(queryset=PropertyPost.objects.all(),
slug_field='pk')
owner = UserSerializer(source="prop_post.owner")
class Meta:
model = Image
fields = (
'url',
'photo',
'prop_post',
'owner',
)

Use SerializerMethodField() that will achieve the task.
Since you haven't posted your models and how it's related.
I gave you the normal idea of how to achieve this.
It will be better if you can add the models as well.
I will be able to update the answer accordingly.
from rest_framework.serializers import SerializerMethodField
class ImageSerializer(serializers.HyperlinkedModelSerializer):
prop_post = serializers.SlugRelatedField(queryset=PropertyPost.objects.all(),
slug_field='pk')
prop_post_title = SerializerMethodField()
class Meta:
model = Image
fields = [
'url',
'photo',
'prop_post',
'prop_post_title',
]
def get_prop_post_title(self, obj):
try:
return obj.prop_post.title
except:
return None

Related

How to upload multiple images in django rest framework

I want to upload multiple images using image model not like a nested serializer
Here is my serializer
class ProjectImageSerializer(ModelSerializer):
class Meta:
model = ProjectImage
fields = (
'id',
'file',
'project',
)
This is the model
class ProjectImage(models.Model):
file = models.ImageField(
upload_to='apps/projects/ProjectImage/file/',
)
user = models.ForeignKey(
'users.User',
on_delete=models.CASCADE,
related_name='project_image_set',
)
project = models.ForeignKey(
'Project',
on_delete=models.CASCADE,
related_name='image_set',
)
created = CreatedField()
last_modified = LastModifiedField()
def __str__(self):
return basename(self.file.name)
and here is Views.py
class ProjectImageViewSet(viewsets.ModelViewSet):
parser_classes = [
MultiPartParser,
]
queryset = ProjectImage.objects.all()
serializer_class = ProjectImageSerializer
can anyone help me when I try with postman its selecting multiple images but posting only one
class ProjectImageSerializer(ModelSerializer):
class Meta:
model = ProjectImage
fields = (
'id',
'file',
'project',
)
read_only_fields = ['id']
extra_kwargs = {'file': {'required': 'True'}}
Try above code
You can't use this serializer for uploading multiple images. You should define another serializer which accepts a list of files in one of the fields. Something like this:
def UploadSerializer(serializers.Serializer):
images = serializers.ListField(child=serializers.ImageField())
And then implement your logic to create ProjectImage instances in the create method.

Django rest framework query? Every todo item jas a teamowner. I want to have a query with all todos per Team. So

class Teams(models.Model):
name = models.CharField(max_length=20)
file = models.FileField(upload_to='team_icons', null='True', blank='True')
members = models.ManyToManyField(User, related_name='member')
class ToDo(models.Model):
title = models.CharField(max_length=200)
description = models.TextField()
owner = models.ForeignKey('auth.user', related_name='todos', on_delete=models.CASCADE)
file = models.FileField(upload_to='uploads', null='True', blank='True')
teamOwner = models.ForeignKey("Teams", related_name='team', on_delete=models.CASCADE)
==> the serializers
class ToDoSerializer(serializers.ModelSerializer):
class Meta:
fields= (
'id',
'title',
'description',
'owner',
'file',
'teamOwner',
)
model = ToDo
class TeamSerializer(serializers.ModelSerializer):
# name = serializers.SerializerMethodField()
class Meta:
fields = (
'id',
'name',
'file',
)
model = Teams
And finally the view code of the query:
class ListTodo(generics.ListCreateAPIView):
queryset = models.ToDo.objects.all()
serializer_class = serializers.ToDoSerializer
def get_queryset(self):
owner_queryset = self.queryset.filter(Teams)
return owner_queryset
Every combination in .filter(xxx) fails. ik want as outcome the Team ID or PK number in the return queryset.
Iam a beginner so i hope i explained my problem in a clear way
you can write like ;
def get_queryset(self):
# if you want to logged user teams' todo list
owner_queryset = self.queryset.filter(Teams=self.request.user)
return owner_queryset
Best regards,

DRY way to rename ModelSerializer fields without duplicating model/field definitions?

Working with a legacy database with an awful schema and want to rename several ModelSerializer fields without having to redefine fields already defined on the model.
Here's an example model:
class LegacyItem(models.Model):
# Note: ignore things that feel "wrong" here (just an example)
legacyitem_id = models.IntegerField(primary_key=True)
legacyitem_notes = models.CharField(max_length=4000, blank=True, null=True)
directory_id = models.ForeignKey('Directory', models.DO_NOTHING)
created_by_directory_id = models.ForeignKey('Directory', models.DO_NOTHING)
created_date = models.DateField(auto_now_add=True)
modified_by_directory_id = models.ForeignKey('Directory', models.DO_NOTHING)
modified_date = models.DateField(auto_now=True)
Here's a working serializer:
class LegacyItemSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = LegacyItem
read_only_fields = [
'created_date',
'modified_date',
]
The goal is to bulk rename model fields for the API so we can abstract away the awful schema. Here's a working serializer showing the sort of renaming we want to do:
class LegacyItemSerializer(serializers.ModelSerializer):
created_by = serializers.PrimaryKeyRelatedField(
read_only=True,
source='created_by_directory_id',
)
customer = serializers.PrimaryKeyRelatedField(
queryset=Directory.objects.all(),
source='directory_id',
)
id = serializers.PrimaryKeyRelatedField(
read_only=True,
source='legacyitem_id'
)
modified_by = serializers.PrimaryKeyRelatedField(
read_only=True,
source='modified_by_directory_id',
)
notes = serializers.DateField(source='legacyitem_notes')
class Meta:
fields = [
'id',
'customer',
'notes',
'created_by',
'created_date',
'modified_by',
'modified_date',
]
model = LegacyItem
read_only_fields = [
'created_date',
'modified_date',
]
All we want to do is rename the fields. We don't want to change the validation and would rather keep most of that validation on the model and the model's fields and not also put it into the serializer. We will have to do this sort of thing for a lot of models and it's very tedious and bad practice (IMO) to be duplicating model validation on the serializer just to rename a field.
Is there a DRY way to do this? Maybe something we can put into LegacyItemSerializer.Meta or some method we can override? When working with Django forms, for example, you could do this easily by tweaking labels/widgets in the ModelForm.Meta. You would never have to redefine ModelForm fields/validation.
In a perfect world, maybe something like:
class LegacyItemSerializer(serializers.ModelSerializer):
class Meta:
model = LegacyItem
model_field_args = {
'legacyitem_id': {'name': 'id'},
'directory_id': {'name': 'customer'},
'legacyitem_notes': {'name': 'notes'},
'created_by_directory_id': {'name': 'created_by'},
'modified_by_directory_id': {'name': 'modified_by'},
}

django class based CreateApiView author_id is not null?

I have also authenticate it with token but when I create a new post error is alert IntegrityError at /api/create/ NOT NULL constraint failed: core_article.author_id how can I valid data with request user in serializer?
model.py
from django.contrib.auth.models import User
from django.db import models
class Article(models.Model):
title = models.CharField(max_length=255, help_text="Short title")
content = models.TextField(blank=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.BooleanField(default=True)
def __str__(self):
return self.title
serializer.py
from rest_framework import serializers
from django.contrib.auth.models import User
from core.models import Article
class NewsSerializer(serializers.ModelSerializer):
author = serializers.SlugRelatedField(
slug_field=User.USERNAME_FIELD, read_only=True, required=False)
class Meta:
model = Article
fields = [
'id',
'author',
'title',
'content',
'status',
]
views.py
class ArticleCreate(CreateAPIView):
queryset = Article.status_objects.all()
serializer_class = NewsSerializer
permission_classes = (permissions.IsAuthenticated, )
I don't know if this is what you're looking for, but you can pass the user as author object to your serializer and in your serializer use that author to create your Article object (Note: I assume that you have used correct authentication_class in your view and have access to user from your request object).
First you need to override the perform create of your view:
class ArticleCreate(CreateAPIView):
queryset = Article.status_objects.all()
serializer_class = NewsSerializer
permission_classes = (permissions.IsAuthenticated, )
def perform_create(self, serializer):
serializer.save(author=self.request.user)
Which will send an user instance to your serializer validated data. Then you should change your serializer to:
class NewsSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = [
'id',
'title',
'content',
'status',
]
Note that the line author = serializers.SlugRelatedField(slug_field=User.USERNAME_FIELD, read_only=True, required=False) and author are removed from your serializer. But if you need to serialize the id of that author (read only purpose) you can change your serializer to:
class NewsSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = [
'id',
'title',
'author',
'content',
'status',
]
read_only_fields = ('author',)
author = serializers.SlugRelatedField(
slug_field=User.USERNAME_FIELD, read_only=True,required=True)
Please change required=False to required=True . If you set True then don't add Null value. So you avoid this errror.

Include attributes from another referenced model in a filtered get request on django REST framework

My goal is to include the name attribute of the Brand model a Product references through models.ForeignKey, when I make a get request for products. Exactly what this piece of code returns in the python shell:
Product.objects.all().values('name', 'brand__name',)
returns this:
[
{'name': 'B-1', 'brand__name': 'B-brand'},
{'name': 'B-2', 'brand__name': 'B-brand'},
{'name': 'C-1', 'brand__name': 'C-brand'}
]
Im already using django-filters to filter my get requests.
Models:
class Brand(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=255)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE, default=None)
def __str__(self):
return self.name
Serializers:
class BrandSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Brand
fields = ('id', 'url', 'name')
class ProductSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Product
fields = ('id', 'url', 'name', 'brand')
Filter:
class ProductFilter(filters.FilterSet):
name = filters.CharFilter(lookup_expr = 'icontains')
brand__name = filters.CharFilter(lookup_expr = 'icontains')
class Meta:
model = Product
fields = ('name' 'brand__name',)
View:
class ProductView(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filterset_class = ProductFilter
with brand__name in the filterSet, i am able to reference the name of the brand model a certain product is referencing and retrieve it. My goal is to also include that same name of the Brand along with the attributes of a product when I make the get request, which currently only yields the url/reference of the brand (along with all other atributes of Product).
If you want to return as a flat dictionary, you can do like this.
class ProductSerializer(serializers.HyperlinkedModelSerializer):
brand_name = serializer.CharField(source="brand__name")
class Meta:
model = Product
fields = ('id', 'url', 'sku', 'name', 'brand_name', 'price')
Ive solved my own issue, by defining brand as brandSerializer in ProductSerializer, i was able to return the whole brand object along with the product info, just like this:
class ProductSerializer(serializers.HyperlinkedModelSerializer):
brand = BrandSerializer()
class Meta:
model = Product
fields = ('id', 'url', 'sku', 'name', 'brand', 'price')