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
.
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'.
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.
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.
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.
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With