Reputation: 1253
I have a model where I create an instance using django rest framework. The serializer complains about a missing slug and an empty ForeignKey-Field that is supposed to point to the User.
I tried to override perform_create
in my serializer to set these values, but I realized that in the standard CreateModelMixin:
class CreateModelMixin(object):
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
the method is_valid()
is called before perform_create()
. Therefore populating the foreign key for user and adding a slug does not work.
Is there a proper way to solve this problem or should I override create
?
Update:
I was asked by @Rahul Gupta to add Model and Serializer. Here they are:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields=('id','name','slug',..., 'shop','category')
and
class Product(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(max_length=255)
shop = models.ForeignKey(Shop)
category = models.ForeignKey("Category")
def __unicode__(self):
return self.name
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Product, self).save(*args, **kwargs)
I should probably make myself a bit clearer. In the browser the user fills in a form to create a new Product
instance. However the user does not enter shop
or slug
, as these are determined by automatically. Slug is derived from name and shop from a different model, that is linked to request.user
.
Upvotes: 2
Views: 1508
Reputation: 11
If you using the rest framework and serializer after add this code in the model:
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Product, self).save(*args, **kwargs)
you need also add this code to the serializer function of the model:
slug = serializers.SlugField(required=False)
and you good to go.
Upvotes: 0
Reputation: 15532
You don't have to copy and paste code from the parent class, you can just call super
in order to borrow functionality from the parent's create
method:
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all().order_by('name')
serializer_class = ProductSerializer
def create(self, request, *args, **kwargs):
request.data['shop'] = drequest.user.shop.id
# Everything above is from Sebastian Langer's answer
# difference is below: just call parent's `create`:
return super(ProductViewSet, self).create(request, *args, **kwargs)
Upvotes: 2
Reputation: 1253
So I'll answer this myself. I've done something rather silly - I thought that I have to override the create method in the serializer when it really seems to be the method in the ViewSet that I have to override. Here is the code that did it for me:
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all().order_by('name')
serializer_class = ProductSerializer
def create(self, request, *args, **kwargs):
request.data['shop']=request.user.shop.id # <-- I ADDED THIS LINE
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
The comment "I ADDED THIS LINE" is in the line where I add functionality to the original method. It does the job, but there might be a more elegant solution. Something similar can be done for the slug.
Upvotes: 1