Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I override Django Rest Framework viewset perform_create() method to set a default value to a field

I have a model called Product and two viewsets that manage the same model in different ways. Each one must set a different value for field product_type, which is set read_only in the serializer SuplementSerializer.

I trying to override perform_create() method and set the value for field product_type, but it always takes the default value.

This is my model:

class Product(models.Model):
    ROOM = 'ROOM'
    SUPLEMENT = 'SUPLEMENT'
    PRODUCT_TYPE_CHOICES = (
        (ROOM, _('Room')),
        (SUPLEMENT, _('Suplement'))
    )

    hotel = models.ForeignKey(Hotel, on_delete=models.PROTECT, related_name='products', verbose_name=_('Hotel'))
    name = models.CharField(max_length=100, verbose_name=_('Name'))
    product_type = models.CharField(max_length=9, choices=PRODUCT_TYPE_CHOICES, default=ROOM, verbose_name=_('Product Type'))
    room_type = models.ForeignKey(RoomType, null=True, blank=True, on_delete=models.PROTECT, related_name='products', verbose_name=_('Room Type'))
    plan_type = models.ForeignKey(PlanType, null=True, blank=True, on_delete=models.PROTECT, related_name='products', verbose_name=_('Plan Type'))
    content_type = models.ForeignKey(ContentType, null=True, blank=True, on_delete=models.PROTECT, related_name='rate_base_products', verbose_name=_('Rate Base'))
    object_id = models.PositiveIntegerField(null=True, blank=True)
    rate_base = GenericForeignKey('content_type', 'object_id')

    class Meta:
        verbose_name = _('Product')
        verbose_name_plural = _('Products')

    def __str__(self):
        return "[{}][{}]{}".format(self.id, self.hotel, self.name)

    def save(self, *vars, **kwargs):
        self.full_clean()
        return super().save(*vars, **kwargs)

    def clean(self, *vars, **kwargs):
        if self.content_type != None:
            if self.content_type.model != 'ages' and self.content_type.model != 'roombase' and self.content_type.model != 'product':
                raise CustomValidation(_("rate_base must be an instance of either 'Ages' or a 'RoomBase'"), 'rate_base', status.HTTP_400_BAD_REQUEST)

These are my viewsets:

class SuplementViewSet(viewsets.ModelViewSet):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = models.Product.objects.filter(product_type=models.Product.SUPLEMENT)
    serializer_class = serializers.SuplementSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
    search_fields = ('hotel__name', 'name')

    def perform_create(self, instance):
        instance.product_type = models.Product.SUPLEMENT
        instance.save()

class ProductViewSet(viewsets.ModelViewSet):
    permission_classes = (permissions.IsAuthenticated,)
    queryset = models.Product.objects.all()
    serializer_class = serializers.ProductSerializer
    filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter,)
    search_fields = ('hotel__name', 'name')
    filter_fields = ('hotel__name', 'name')

And this is my serializer:

class SuplementSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Product
        fields = ('id', 'hotel', 'product_type', 'name')
        read_only_fields = ('product_type',)

    def __init__(self, *args, **kwargs):
        exclude = kwargs.pop('exclude', None)

        super(SuplementSerializer, self).__init__(*args, **kwargs)

        if exclude is not None:
            for field_name in exclude:
                self.fields.pop(field_name)

I don't know why I can't set the value for field product_type.

like image 502
HuLu ViCa Avatar asked Jul 11 '18 03:07

HuLu ViCa


People also ask

What is ViewSet in Django REST framework?

Django REST framework allows you to combine the logic for a set of related views in a single class, called a ViewSet . In other frameworks you may also find conceptually similar implementations named something like 'Resources' or 'Controllers'.

What is Perform_create in django?

perform_create. perform create method is used to add extra information when creating a new object. perform_create() method will not execute if you override create() method.

What is difference between APIView and ViewSet?

APIView allow us to define functions that match standard HTTP methods like GET, POST, PUT, PATCH, etc. Viewsets allow us to define functions that match to common API object actions like : LIST, CREATE, RETRIEVE, UPDATE, etc.

How to write views in Django REST-framework?

Now we can use the serializers to write views. Django Rest-Framework supports two different types of views. We’ll use ViewSets (Class Based Views). ViewSets works exactly same as Generic Views. The only difference is using ViewSet you don’t have to create separate views for getting list of objects and detail of one object.

What is a viewset in Django rest?

After routing has determined which controller to use for a request, your controller is responsible for making sense of the request and producing the appropriate output. Django REST framework allows you to combine the logic for a set of related views in a single class, called a ViewSet.

What are the generic views in REST framework?

The generic views provided by REST framework allow you to quickly build API views that map closely to your database models. If the generic views don't suit the needs of your API, you can drop down to using the regular APIView class, or reuse the mixins and base classes used by the generic views to compose your own set of reusable generic views.

What are the different types of views in REST-framework?

Django Rest-Framework supports two different types of views. We’ll use ViewSets (Class Based Views). ViewSets works exactly same as Generic Views. The only difference is using ViewSet you don’t have to create separate views for getting list of objects and detail of one object.


1 Answers

Argument to perform_create() method is serializer instance not an object instance. You can set the field as below

def perform_create(self, serz):
    serz.save(product_type=models.Product.SUPLEMENT)

See explanation here http://www.django-rest-framework.org/tutorial/6-viewsets-and-routers/#refactoring-to-use-viewsets

like image 50
Rohan Avatar answered Oct 29 '22 12:10

Rohan