Reputation: 483
I currently have a model called "Review" where I have a "unique_together" constraint so one user can only write one review per post.
class Review(models.Model):
created = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(User, related_name='reviews', on_delete=models.SET_NULL, null=True)
post = models.ForeignKey(Post, related_name='reviews', on_delete=models.CASCADE)
rating = models.IntegerField()
comment = models.TextField(blank=True, null=True)
class Meta:
unique_together = ['user', 'post']
And in my View I am grabbing the user from the request (I'm using token authentication) and use that user to save the object by overwriting the "perform_create" method:
class ReviewCreateView(CreateAPIView):
permission_classes = [IsAuthenticated]
serializer_class = ReviewCreateSerializer
def perform_create(self, serializer):
serializer.save(user=self.request.user)
And my serializer looks like this:
class ReviewCreateSerializer(ModelSerializer):
class Meta:
model = Review
fields = ['post', 'rating', 'comment']
When I try to submit two reviews to the same post by the same user I get an internal server error.
The body of my HTTP POST request looks like this:
{
"post" : 11,
"rating": 1,
"comment": "this is a great post"
}
Instead of getting an error response (for example 403 error). I get this Django server error instead:
django.db.utils.IntegrityError: duplicate key value violates unique constraint
After spending some time researching I saw that Django Rest Framework provides the "UniqueTogetherValidator". So I added it like this:
class ReviewCreateSerializer(ModelSerializer):
class Meta:
model = Review
fields = ['post', 'rating', 'comment']
validators = [
UniqueTogetherValidator(
queryset=Review.objects.all(),
fields=['user', 'post']
)
]
But then the issue I'm having is that it errors because it can't find the key "user", I'm guessing because I dont have a "user" field in my HTTP request body (since the user is being grabbed by Django using the authentication token). I get the following error:
KeyError: 'user'
I also tried adding the 'user' to my serializer fields:
fields = ['user', 'post', 'rating', 'comment']
But I get the following error response:
{
"user": [
"This field is required."
]
}
I would really appreciate some help to solve this issue. Many thanks!
Upvotes: 1
Views: 1155
Reputation: 6296
Try using the CurrentUserDefault serializer field so that the user can be retrieved implicitly for the validation.
class ReviewCreateSerializer(ModelSerializer):
user = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
class Meta:
model = Review
fields = fields = ['user', 'post', 'rating', 'comment']
validators = [
UniqueTogetherValidator(
queryset=Review.objects.all(),
fields=['user', 'post']
)
]
Also, with this, you no longer have to pass the user to the serializer save method as it is already present in the serializer. So you can get rid of the overridden perform_create()
method in your view
Upvotes: 2