0

I am working with django rest framework. I have Product and Review models. Review is related to Product like so;

class Product(models.Model):
    name = models.CharField(max_length=200, null=False, blank=False)
    description = models.TextField(max_length=2000, null=False, blank=False)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)
    slug = models.SlugField(unique=True)
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    is_featured = models.BooleanField(default=False)
    created= models.DateTimeField(auto_now_add=True)

class Review(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    product= models.ForeignKey(Product, on_delete=models.CASCADE)
    title = models.CharField(max_length=80, blank=False, null=False)
    body = models.TextField(max_length=400, blank=False, null=False)
    is_approved = models.BooleanField(default=False)
    created = models.DateTimeField(auto_now_add=True)

I wrote a serializer class for the review:

class ReviewSerializer(serializers.ModelSerializer):
    author = UserSerializer(read_only=True)
    class Meta:
        model = Review
        fields = ['id', 'author', 'title', 'body', 'is_approved', 'created']

    def create(self, validated_data):
        title = validated_data.get('title')
        body = validated_data.get('body')
        author = self.context['request'].user
        review = Review.objects.create(title=title, body=body, author=author)
        return review

and in my views.py, i have this;

class ReviewCreateView(CreateAPIView):
    serializer_class = ReviewSerializer
    queryset = Review.objects.all()
    permission_classes = [IsAuthenticated,]
    authentication_classes = [TokenAuthentication,]

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        product_id = kwargs.get('product')
        product = Product.objects.get(id=product_id)
        serializer.save(product=product)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

in my urls urlpatterns:

path('api/review/new/<product>/', ReviewCreateView.as_view(), name="create-review"),

Issue is when i send a review from the frontend to that api, i keep getting a Not Null constraint error like so: IntegrityError at /api/review/new/23/ NOT NULL constraint failed: products_review.product_id

I have handled the product saving inside the CreateAPIView in my views, but for some reasons Django isn't picking it. How do i make this work please? Any assistance will be appreciated. Please note that answers for similar questions i found here didn't work for me.

2
  • Call serializer .save() in the view will create a new instance, but you saved also in Serializer.create method using create, here you just need to return a instance ready for save Commented Jun 30, 2020 at 10:54
  • @minglyu thanks. You mean in serializer i'm not supposed to save? Commented Jun 30, 2020 at 11:34

1 Answer 1

2

You are almost right. You passed the product instance, so it should be included in the validated_data for the ReviewSerializer.create method. But you don't use it when you are actually creating the review instance.

class ReviewSerializer(serializers.ModelSerializer):
    author = UserSerializer(read_only=True)
    class Meta:
        model = Review
        fields = ['id', 'author', 'title', 'body', 'is_approved', 'created']

    def create(self, validated_data):
        title = validated_data.get('title')
        body = validated_data.get('body')
        author = self.context['request'].user
        product = validated_data.get('product')
        review = Review.objects.create(
            title=title, 
            body=body, 
            author=author, 
            product=product
        )
    return review

https://www.django-rest-framework.org/api-guide/serializers/#passing-additional-attributes-to-save

Also why can't you just have a product field on your review serializer?

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks @c6754. I passed the product as a kwarg in the url, using the product ID,not as part of the request data, so I don't think it will be part of the validated data.
Can you print out the value of product in the ReviewSerializer.create method before the Review.objects.create method is called?
I think @c6754 is right. Review.objects.create(title=title, body=body, author=author) attempts to save the review, but you don't have a product yet. Try to use Review(title=title, body=body, author=author) instead to create an unsaved instance and then save in the view once product is set.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.