'One review per user in the current title
I am trying to make so that every user could only post one review per title (product). First idea was to do this through UniqueTogether, but it resulted unsuccessful. So now, I thought to complete it by validate in serializer.
Right now I am getting the following error:
TypeError: Review() got an unexpected keyword argument 'title'. But if you look at my code below I did not pass title argument to Review(). I even tried to make error on purpose to see what arguments I can pass to Review() and title was not there.
django.core.exceptions.FieldError: Cannot resolve keyword 'title_d' into field. Choices are: author,
author_id, comments, id, pub_date, score, text, title_id, title_id_id
serializers.py
class ReviewSerializer(serializers.ModelSerializer):
author = serializers.SlugRelatedField(
slug_field='username',
default=serializers.CurrentUserDefault(),
read_only=True
)
class Meta:
model = Review
fields = ('id', 'text', 'author', 'score', 'pub_date')
def validate(self, data):
title_id = self.context['view'].kwargs['title_id']
author = self.context['request'].user
if Review.objects.filter(title_id=title_id, author=author).exists():
raise serializers.ValidationError(
'You cannot post second review on same item.'
)
return data
models.py
class Review(models.Model):
title_id = models.ForeignKey(
Title,
on_delete=models.DO_NOTHING,
related_name='reviews'
)
text = models.TextField(
'Текст отзыва'
)
author = models.ForeignKey(
User,
on_delete=models.DO_NOTHING,
verbose_name='Автор',
related_name='reviews'
)
score = models.IntegerField(
choices=SCORES
)
pub_date = models.DateTimeField(
'Дата публикации',
auto_now_add=True,)
class Title(models.Model):
name = models.CharField(
max_length=255,
verbose_name='Название произведения'
)
year = models.IntegerField(
verbose_name='Год произведения'
)
category = models.ForeignKey(
Category,
on_delete=models.DO_NOTHING,
verbose_name='Категория произведения',
related_name='category_title',
)
description = models.TextField(
verbose_name='Описания произведения',
blank=True,
null=True
)
rating = models.IntegerField(
verbose_name='Рейтинг произведения',
blank=True,
null=True
)
genres = models.ManyToManyField(
Genre,
through='GenreTitle',
)
views.py
class ReviewViewSet(viewsets.ModelViewSet):
serializer_class = ReviewSerializer
pagination_class = LimitOffsetPagination
permission_classes = [ReviewAndComment, IsAuthenticatedOrReadOnly]
def get_queryset(self):
title = get_object_or_404(Title, id=self.kwargs['title_id'])
return title.reviews.all()
def perform_create(self, serializer):
title = get_object_or_404(Title,
id=self.kwargs['title_id'])
author = get_object_or_404(User,
username=self.request.user)
reviews = Review.objects.filter(title=title.pk)
scores = reviews.values_list('score', flat=True)
scores = list(scores)
scores.append(serializer.validated_data['score'])
rating = sum(scores) / len(scores)
title.rating = round(rating)
title.save()
serializer.save(title=title,
author=author)
Solution 1:[1]
Change name of title_id field into 'title'. Also in validation do one change:
def validate(self, data):
title = int(data['title'])
author = self.context['request'].user # here maybe self.request.user might work too
if Review.objects.filter(title=title, author=author).exists():
...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | NixonSparrow |
