DRF : AttributeError: 'BlogSerializers' object has no attribute 'get_uri' - python

Can anyone explain about the problem.
mobel.py
class Blog(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=120, null=True, blank=True)
content = models.TextField(null=True, blank=True)
timestamp = models.DateTimeField(auto_now_add=True)
def get_api_url(self):
return api_reverse("post-rud", kwargs={"pk": self.pk})
and my serializer file is serializer.py
class BlogSerializers(serializers.ModelSerializer):
uri = serializers.SerializerMethodField(read_only=True)
class Meta:
model = Blog
fields = [
'uri',
'pk',
'user',
'title',
'content',
'timestamp',
]
read_only_fields = ['pk', 'user']
def get_uri(self, obj):
return obj.get_api_url()
error showing
AttributeError at /api/blog/post/list/ 'BlogSerializers' object has no
attribute 'get_uri'
if i use under this line than problem is solved. But i wanna understand about this error.
class BlogSerializers(serializers.ModelSerializer):
# uri = serializers.CharField(read_only=True, source='get_api_url')

You added the get_uri method to the meta Class, instead of your serializer class.
Just remove one indentation level and you are good to go.

Related

DRF Add annotated field to nested serializer

I have two serializers that represent comments and their nested comments. I'm provide a queryset to viewset with annotated field likes. But my problem is that field only working in parent serializer. When i add this field to nested serializer i got error
Got AttributeError when attempting to get a value for field likes on serializer CommentChildrenSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Comment instance.
Original exception text was: 'Comment' object has no attribute 'likes'.
Here is some my code. Thanks
Models.py
class Post(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
slug = models.SlugField(blank=True)
body = models.TextField()
tags = TaggableManager(blank=True)
pub_date = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-pub_date']
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE,
related_name='comments')
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
text = models.TextField(max_length=500)
pub_date = models.DateTimeField(auto_now=True)
parent = models.ForeignKey('self', blank=True, null=True,
on_delete=models.CASCADE, related_name='children')
class Meta:
ordering = ['-pub_date']
class Vote(models.Model):
comment = models.ForeignKey(Comment, on_delete=models.CASCADE,
related_name='votes')
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
choice = models.BooleanField(null=True)
Serializers.py
class PostRetrieveSerializer(PostSerializer):
comments = CommentSerializer(read_only=True, many=True)
author = AuthorInfoSerializer(serializers.ModelSerializer)
class Meta:
model = Post
fields = ['id', 'author', 'slug', 'title', 'body', 'tags', 'pub_date', 'comments']
class CommentChildrenSerializer(serializers.ModelSerializer):
author = AuthorInfoSerializer(read_only=True)
likes = serializers.IntegerField()
class Meta:
model = Comment
fields = ['author', 'id', 'text', 'pub_date', 'parent', 'likes']
class CommentSerializer(serializers.ModelSerializer):
author = AuthorInfoSerializer(read_only=True)
children = CommentChildrenSerializer(many=True)
likes = serializers.IntegerField()
class Meta:
ordering = ['pub_date']
model = Comment
fields = ['author', 'id', 'text', 'pub_date', 'children', 'likes']
Views.py
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all().prefetch_related(
Prefetch('comments', queryset=Comment.objects.filter(parent__isnull=True)
.annotate(likes=Count('votes__choice'))))
serializer_class = PostSerializer
permission_classes = [IsOwnerOrAdminOrReadOnly]
pagination_class = PostPagination
lookup_field = 'slug'
def get_serializer_class(self):
""""
Attach related comments
when get post detail
"""
if self.action == 'retrieve':
return PostRetrieveSerializer
return self.serializer_class
def perform_create(self, serializer):
serializer.save(author=self.request.user)
maybe you can do something like this, adding the like field in each child comment.
queryset = Post.objects.all()\
.prefetch_related(
Prefetch(
'comments',
queryset=Comment.objects\
.filter(parent__isnull=True)\
.annotate(likes=Count('votes__choice'))\
.prefetch_related(
'children',
queryset=Comments.objects.all()\
.annotate(likes=Count('votes__choice'))
)
)
)
I hope this help you.
Regards!
On your model level, add a custom property like the below.
class Comment(models.Model):
...
class Meta:
ordering = ['-pub_date']
#property
def likes(self):
return self.votes.count()
On your serializer add SerializerMethodField
class CommentChildrenSerializer(serializers.ModelSerializer):
author = AuthorInfoSerializer(read_only=True)
likes = serializers.SerializerMethodField() # Change here
class Meta:
model = Comment
fields = ['author', 'id', 'text', 'pub_date', 'parent', 'likes']
# method for the SerializerMethodField
def get_likes(self, obj):
return obj.likes
Update both Comment related serializers. I believe this approach is simpler than the current implementation.

DRF post to model with a many-to-many field

I have the following models:
class Tag(TimeStampModel):
name = models.CharField(unique=True, max_length=100)
slug = models.SlugField(max_length=100, unique=True, blank=True)
featured = models.BooleanField(default=False, blank=True)
class Deal(VoteModel, models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='deals',
on_delete=models.CASCADE)
title = models.CharField(max_length=1024, blank=False, null=False)
slug = models.SlugField(max_length=1024, unique=True, blank=True)
description = models.TextField(blank=False, null=False)
poster = models.ImageField(blank=True)
tags = models.ManyToManyField(
Tag, blank=True)
And the following serializers:
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ['id', 'name', 'slug', 'featured', 'created_at']
class DealSerializer(serializers.ModelSerializer):
user = UserSerializer(many=False, read_only=True)
tags = TagSerializer(many=True, read_only=True)
tags_ids = serializers.PrimaryKeyRelatedField(many=True, write_only=True, queryset=Tag.objects.all())
class Meta:
model = Deal
fields = '__all__'
Views
class DealList(viewsets.ModelViewSet, VoteMixin):
serializer_class = DealSerializer
permission_classes = [IsOwnerOrAdminOrReadOnly]
def get_queryset(self):
return Deal.objects.all()
def perform_create(self, serializer):
serializer.save(user=self.request.user)
I am able to get the data and also post it, but because of the many-to-many field (tags), I seem to have some issues as a Deal may have tags that only exist (created beforehand, and cannot be created through a post request to the Deal).
I send data as the following:
{
title: 'some title',
all_other_fields: 'some data',
tags_ids: [2, 4]
}
The tags are sent as an array of tag ids, but I get an error as the following:
"Incorrect type. Expected pk value, received str."
I only added the tags_ids so I could perform write operations on it as I couldn't figure out a way to use the field tags as both a read and write field that would return an object on read, and accept an id on write.
I have read through many posts here on Stackoverflow, but nothing that would work for me yet. Any help would be very appreciated. Thank you.
Try changing your serializer like this
class DealSerializer(serializers.ModelSerializer):
user = UserSerializer(many=False, read_only=True)
tags = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all())
class Meta:
model = Deal
fields = '__all__'
Try doing it this way.
class DealSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
tags = TagSerializer(read_only=True)
class Meta:
model = Deal
fields = ('user', 'title', 'slug', 'description', 'poster', 'tags')

Django viewset error: 'QuerySet' object has no attribute 'title'

I'm trying to create a ViewSet for the Course model (to simply display all courses), but I'm getting the following error when trying to access it. I'm new to creating ViewSets and Django in general, what am I doing wrong?
Django 2.2
Error
AttributeError: Got AttributeError when attempting to get a value for field `title` on serializer `CourseSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `QuerySet` instance.
Original exception text was: 'QuerySet' object has no attribute 'title'.
CourseViewSet
class CourseViewSet(viewsets.ModelViewSet):
def list(self, request):
queryset = Course.objects.all()
serializer = CourseSerializer(queryset)
return Response(serializer.data)
CourseSerializer
class CourseSerializer(serializers.ModelSerializer):
class Meta:
model = Course
fields = (
'id',
'title',
'description',
'active',
'individual_result',
'course_duration',
'video',
'manager_id'
)
models/Course
class Course(models.Model):
title = models.CharField(max_length=255, blank=False, null=False)
description = models.CharField(max_length=255, blank=True, null=True)
active = models.BooleanField(default=True)
individual_result = models.BooleanField(default=False)
course_duration = models.CharField(max_length=255, blank=True, null=True)
video = models.CharField(max_length=255, blank=True, null=True)
manager_id = models.ForeignKey(User, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.title
You should serialize with many=True, since a queryset is a collection of objects that can contain zero, one, or more elements:
serializer = CourseSerializer(queryset, many=True)
For more information, see the Dealing with multiple objects section [drf-doc].

How to make a ManyToMany serialization to be able to create a object in the POST request?

I'm trying to create a serialize to handle a ManyToMany relation, but it's not working. I have read the documentation and I probably doing something wrong. Also I have read the answers here.
Here are my models.
class Author(models.Model):
name = models.CharField(verbose_name="Name", max_length=255)
class Book(models.Model):
author = models.ForeignKey(
Author,
related_name="id_author",
blank=True,
null=True,
on_delete=models.PROTECT)
price = models.FloatField(verbose_name="Price")
class FiscalDocument(models.Model):
seller = models.ForeignKey(
User,
related_name="user_id",
on_delete=models.PROTECT)
book = models.ManyToManyField(Book)
My serializer:
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ('id', 'name')
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ('id', 'author', 'price')
def to_representation(self, instance):
response = super().to_representation(instance)
response['author'] = AuthorSerializer(instance.author).data
return response
class FiscalDocumentSerializer(serializers.ModelSerializer):
book = BookSerializer()
class Meta:
model = FiscalDocument
fields = ('id', 'seller', 'book')
def create(self, validated_data):
book_data = validated_data.pop('book')
fiscal_document = FiscalDocument.objects.create(**validated_data)
Book.objects.create(FiscalDocument=FiscalDocument,**medicine_data)
return fiscal_document
When I try to access the endpoint of the FiscalDocument, django-rest-framework is throwing an error:
Got AttributeError when attempting to get a value for field price on serializer BookSerializer. The serializer field might be named incorrectly and not match any attribute or key on the ManyRelatedManager instance. Original exception text was: ManyRelatedManager object has no attribute price.
If anyone can help XD.

django-rest-framwork got AttributeError when attempting to get a value for field

I want to get all prodcut table values with join product_ratings table. I did somthing like this but this code give me AttributeError. So I did product_ratings = ProductRatingSerializer(many=True)
in product serializer and used this value in the field, but it's not working:
The full error message:
Got AttributeError when attempting to get a value for field `product_ratings` on serializer `ProductSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Product` instance.
Original exception text was: 'Product' object has no attribute 'product_ratings'.
view :
class StoreApiView(mixins.CreateModelMixin, generics.ListAPIView):
lookup_field = 'pk'
serializer_class = ProductSerializer
def get_queryset(self):
qs = Product.objects.all()
query = self.request.GET.get('q')
if query is not None:
qs = qs.filter(
Q(title__icontains=query) |
Q(description__icontains=query)
).distinct()
return qs
its serializer classes:
class ProductRatingSerializer(ModelSerializer):
class Meta:
model = Product_ratings
fields = [
'p_id',
'commenter',
'comment',
'rating',
'created_date',
]
read_only_fields = ['p_id']
class ProductSerializer(ModelSerializer):
product_ratings = ProductRatingSerializer(many=True)
author = serializers.SerializerMethodField()
def get_author(self, obj):
return obj.author.first_name
class Meta:
model = Product
fields = [
'product_id',
'author',
'category',
'title',
'description',
'filepath',
'price',
'created_date',
'updated_date',
'product_ratings',
]
read_only_fields = ['product_id', 'created_date', 'updated_date', 'author']
related model class :
class Product(models.Model):
product_id = models.AutoField(primary_key=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, db_index=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, to_field='cat_id')
title = models.CharField(max_length=120)
description = models.TextField(null=True, blank=True)
price = models.CharField(max_length=50, null=True, blank=True)
filepath = models.CharField(max_length=100, null=True, blank=True)
created_date = models.DateTimeField(auto_now_add=True)
updated_date = models.DateTimeField(auto_now=True)
class Product_ratings(models.Model):
p_id = models.ForeignKey(Product, on_delete=models.CASCADE, to_field='product_id')
commenter = models.ForeignKey(User, on_delete=models.CASCADE)
comment = models.CharField(max_length=200, null=True, blank=True)
rating = models.IntegerField(null=True, blank=True)
created_date = models.DateTimeField(auto_now_add=True)
Default reverse lookup name for ForeignKey is <mode>_set or product_ratings_set in your case, so you need to replace product_ratings field in ProductSerializer with product_ratings_set:
class ProductSerializer(ModelSerializer):
product_ratings_set = ProductRatingSerializer(many=True)
...
class Meta:
model = Product
fields = [
...
'product_ratings_set'
]
Also you can add related_name='product_ratings' attribute to model's ForeignKey to change reverse lookup name, in this case you don't need too change serializer:
class Product_ratings(models.Model):
p_id = models.ForeignKey(Product, on_delete=models.CASCADE, to_field='product_id', related_name='product_ratings')
in my case I had to return just single object from my views.py but I was returning queryset, so changing objects.filter to objects.get fixed the issue for me
Selected answer doesn't work for me. However following way worked:
product_ratings = ProductRatingSerializer(many=True)
Also remember to put product_ratings in related_name field like this:
p_id = models.ForeignKey(Product, on_delete=models.CASCADE, to_field='product_id', related_name='product_ratings')
Here is how Meta class looks:
class Meta:
model = Product
fields = [
...
'product_ratings'
]
I got this error when I had passed the queryset without many=True to the serializer object
qs = SomeObject.objects.all()
srz = SomeObjectSerializer(instance=qs)
srz.data # error happens here
# correct 1
qs = SomeObject.objects.all()
srz = SomeObjectSerializer(qs, many=True)
srz.data
# correct 2
qs = SomeObject.objects.filter(id=some_id).first()
srz = SomeObjectSerializer(qs)
srz.data
general tip:
-if many=False (default) you must pass an object for instance argument in Serializer
-or if you pass a queryset you must also pass many=True to Serializer

Categories