I have a HyperlinkedModelSerializer. To implement its validate method properly, I need to access the primary key or the URL of the object that is being validated – if it has one, i.e. if it's being edited, not created. What's the correct way of doing that?
I tried many things, but the only approach that worked was a hack that fetches the ID of the object when the serializer is instantiated into it's id field:
class BoxSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Box
fields = ('id', 'name', 'url')
def __init__(self, *args, **kwargs):
super(BoxSerializer, self).__init__(*args, **kwargs)
self.id = None \
if len(args) != 1 or not isinstance(args[0], Box) \
else args[0].id
def validate(self, data):
print(data)
return data
What's the proper way to access the ID/URL of the object being validated from within the serializer's validate method? Neither data['id'] nor data['url'] exist.
urls.py:
urlpatterns = [
url(r'(?P<pk>[0-9]+)/$', views.BoxDetail.as_view(), name='box-detail'),
]
views.py:
class BoxDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Box.objects.all()
serializer_class = BoxSerializer
You can access the id of the object being edited by self.instance.
From the DRF serializers docs on Accessing the initial data and instance:
When passing an initial object or queryset to a serializer instance, the object will be made available as
.instance. If no initial object is passed then the.instanceattribute will beNone.
Since you are using HyperLinkedModelSerializer, you will have access to the object being edited in case of PUT requests as an instance attribute set on the serializer. You can use this instance attribute to access the id of the object being edited by doing self.instance.id.
You can write your validation logic in validate() function then after getting the object id in the variable object_id. This will not affect create requests as instance will not be set on the serializer then.
class BoxSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Box
fields = ('id', 'name', 'url')
def validate(self, data):
if self.instance: # 'instance' will be set in case of `PUT` request i.e update
object_id = self.instance.id # get the 'id' for the instance
# write your validation logic based on the object id here
return data
Another way to access the object id is by accessing the kwargs from the view object in the serializer context dictionary.
my_view = self.context['view'] # get the 'view' object from serializer context
object_id = my_view.kwargs.get('pk') # access the 'view' kwargs and lookup for 'pk'
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