How to upload multiple images in django rest framework - django

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.

Related

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,

DRF get only the first serialized instance for list view?

I'm working on a real estate app and want the listings to show only the first image of the Listing. Currently it is showing all images.
class Image(models.Model):
photo = models.ImageField(blank=True, upload_to=get_image_filename)
listing = models.ForeignKey(Listing, on_delete=models.CASCADE)
class ImageSerializerForListingList(serializers.ModelSerializer):
photo = serializers.ImageField()
class Meta:
model = Image
fields = ('photo', )
class ListingListSerializer(serializers.HyperlinkedModelSerializer):
image = ImageSerializerForListingList(many=True, required=False, source='image_set')
class Meta:
model = Listing
fields = ('url', 'address', 'image', )
def get_first_image(self, obj):
image = obj.image_set.all().first()
return ImageSerializerForListingList(image, many=True).data
This is still showing all images,
Any advice on this?
solution
"Although you define the get_first_image method on the ListingListSerializer, you are not using it anywhere.
The methods defined on the serializers only get used implicitly when there is a corresponding SerializerMethodField defined on the serializer."
class ListingListSerializer(serializers.HyperlinkedModelSerializer):
first_image = serializers.SerializerMethodField()
class Meta:
model = Listing
fields = ('url', 'address', 'first_image', )
"""Much like our web app our listing view should only show one Image"""
def get_first_image(self, obj):
image = obj.image_set.first()
return FirstImageSerializer(image).data

How to get a request user query without hitting DB each time in django?

I built some Blog API but I've got an issue.
In the serializer, there is a method field that returns request user has liked the post or not. The problem is this field hits the user DB each time a post returns, which means if 1000 posts are returned, user DB would be hit 1000 times.
How can I avoid this? The first idea was to assign the request user to something like a global variable, but I don't know how to.
this is serializer
class DashboardSerializer(serializers.ModelSerializer):
image = serializers.ImageField(allow_null=True, use_url=True)
likes_count = serializers.SerializerMethodField(read_only=True)
tags = TagSerializer(many=True, read_only=True)
user_has_liked = serializers.SerializerMethodField(read_only=True)
owner = UserField(read_only=True)
comments = CommentsField(read_only=True, many=True, source='two_latest_comments')
comments_count = serializers.SerializerMethodField()
class Meta:
model = Blog
fields = ['id', 'title', 'owner', 'likes_count', 'user_has_liked',
'image', 'video', 'tags', 'get_elapsed_time_after_created',
'comments', 'comments_count']
ordering = ['created_at']
def get_likes_count(self, instance):
return instance.likes.count()
def get_user_has_liked(self, instance):
request = self.context.get('request')
***return instance.likes.filter(pk=request.user.pk).exists()***
*******request.user.pk hits the DB.*********
def get_comments_count(self, instance):
return instance.comments.count()
Thank you in advance.
Use .annotate and Exists subqyery on the queryset that you are passing to the serializer, and then adjust the fields:
serializer call:
queryset = ... # your queryset
user_commented = Comment.objects.filter(
blog_id=OuterRef("pk"),
user_id=request.user.pk,
)
data = DashboardSerializer(instance=queryset.annotate(
likes_count=Count("likes"),
comments_count=Count("comments"),
user_has_liked=Exists(user_commented),
)
serializer:
class DashboardSerializer(serializers.ModelSerializer):
image = serializers.ImageField(allow_null=True, use_url=True)
likes_count = serializers.IntegerField(read_only=True)
tags = TagSerializer(many=True, read_only=True)
user_has_liked = serializers.BooleanField(read_only=True)
owner = UserField(read_only=True)
comments = CommentsField(read_only=True, many=True, source='two_latest_comments')
comments_count = serializers.IntegerField(read_only=True)
class Meta:
model = Blog
fields = ['id', 'title', 'owner', 'likes_count', 'user_has_liked',
'image', 'video', 'tags', 'get_elapsed_time_after_created',
'comments', 'comments_count']
ordering = ['created_at']

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

Serializing a field of the related model in a model DRF

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