Ad

DRF Serializer IntegerField Validation To Make Sure ForeignKey Does Exists

I've a ModelSerializer class which uses an IntegerField as a replace for a ForeingKey relation.

class CartItemCreateSerializer(serializers.ModelSerializer):
    product_id = serializers.IntegerField()

    class Meta:
        model = CartItem
        fields = ('id', 'product_id', 'quantity')

    def validate_product_id(self, value):
        if not Product.objects.filter(pk=value).exists():
            raise serializers.ValidationError('Product not found')
        return value

    def save(self, **kwargs):
        product_id = self.validated_data['product_id']
        cart_id = self.context['cart_id']
        product = Product.objects.get(id=product_id)
        # product = get_object_or_404(Product, id=product_id)
        cart_item, _ = CartItem.objects.get_or_create(
            cart_id=cart_id, product=product)
        cart_item.quantity += self.validated_data['quantity']
        cart_item.save()
        self.instance = cart_item
        return self.instance

I've two questions about this class, first regarding the code, the validate_product_id method does a db call to check if the requested Product object exists and then inside the save method there is another call to db to get the same Product again, I think this way is not optimized for querying the same object twice. Is there a better way to check for the existence or raising proper error? second if I use get_object_or_404 the amount of code to write will decrease but there is no chance to raise a concise but relevant Error Message, so What do you usually do?

Ad

Answer

Usually one would use a special field type PrimaryKeyRelatedField. You don't even need to manually declare one, as it can be done automatically by the ModelSerializer.

class CartItemCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = CartItem
        fields = ('id', 'product', 'quantity')

    def save(self, **kwargs):
        cart_id = self.context['cart_id']
        product = self.validated_data['product']
        cart_item, _ = CartItem.objects.get_or_create(
            cart_id=cart_id, product=product)
        cart_item.quantity += self.validated_data['quantity']
        cart_item.save()
        self.instance = cart_item
        return self.instance

https://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield

Ad
source: stackoverflow.com
Ad