Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django REST Framework: Get ID/URL during validation?

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
like image 454
theV0ID Avatar asked Jul 28 '15 11:07

theV0ID


1 Answers

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 .instance attribute will be None.

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' 
like image 162
Rahul Gupta Avatar answered Oct 11 '22 02:10

Rahul Gupta