Reputation: 483
I have a Viewset where a user can create reviews for a specific product and list their all the reviews they have created for all products:
class ProductReviewViewset(CreateModelMixin, ListModelMixin, GenericViewSet):
serializer_class = ProductReviewSerializer
def get_queryset(self):
# Return all reviews for user that are not marked as deleted
user = self.request.user
return ProductReview.objects.filter(user=user, deleted=False).order_by('review__name')
def perform_create(self, serializer):
# Add user to review object before saving
user = self.request.user
serializer.save(user=self.request.user)
The problem is that this allows the user to create multiple reviews for the same object. I wanted to prevent this, and only allow to create a review if there is no other review already created for that product (reviews marked as "deleted" will not be counted).
So far I was able to override the .create() method and do the serialization, validation and checking for duplicates in there.
class ProductReviewViewset(CreateModelMixin, ListModelMixin, GenericViewSet):
serializer_class = ProductReviewSerializer
def get_queryset(self):
# Return all reviews for user that are not marked as deleted
user = self.request.user
return ProductReview.objects.filter(user=user, deleted=False).order_by('review__name')
def create(self, request, *args, **kwargs):
# Override create method to prevent duplicate object creation
serializer = ProductReviewSerializer(data=self.request.data)
serializer.is_valid(raise_exception=True)
user = self.request.user
product = serializer.validated_data['product']
exists = ProductReview.objects.filter(user=user, product=product, deleted=False).exists()
if not exists:
serializer.save(user=user)
return Response(status=status.HTTP_201_CREATED)
else:
return Response(status=status.HTTP_409_CONFLICT)
Is there an easier or better way of doing this? Or is this the way to do it?
Thanks!
Upvotes: 2
Views: 3734
Reputation: 1623
An alternative would be using get_or_create
queryset method : get_or_create
def create(self, request, *args, **kwargs):
# Override create method to prevent duplicate object creation
serializer = ProductReviewSerializer(data=self.request.data)
serializer.is_valid(raise_exception=True)
user = self.request.user
product = serializer.validated_data['product']
obj, created = ProductReview.objects.get_or_create(user=user, product=product, deleted=False, defaults=seriaizer.validated_data)
if not created:
serializer.save(user=user)
return Response(status=status.HTTP_201_CREATED)
else:
return Response(status=status.HTTP_409_CONFLICT)
the get_or_create
will prevent race conditions
, when request made in parallel
Upvotes: 2