【问题标题】:Django REST Framework: Get ID/URL during validation?Django REST Framework:在验证期间获取 ID/URL?
【发布时间】:2015-10-18 22:25:02
【问题描述】:

我有一个HyperlinkedModelSerializer。要正确实现其validate 方法,我需要访问正在验证的对象的主键URL——如果它有一个,即如果它正在已编辑,未创建。这样做的正确方法是什么?

我尝试了很多方法,但唯一有效的方法是在序列化程序实例化到它的 id 字段时获取对象的 ID:

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

从序列化程序的 validate 方法中访问正在验证的对象的 ID/URL 的正确方法是什么? data['id']data['url'] 都不存在。


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

【问题讨论】:

    标签: django django-views django-rest-framework


    【解决方案1】:

    使用context 属性调用序列化程序。

    serializer = BoxSerializer(queryset, context={'request': self.request}, ...)
    

    现在您可以使用 validate 函数访问 request 对象

    self.context['request']['id']
    

    【讨论】:

    • 我正在使用带有serializer_class=MySerializer 指令的generics.RetrieveUpdateDestroyAPIView,但是来自序列化程序的validate 方法内部的self.context['request']['id'] 给了我一个TypeError: "'Request' 对象不可下标”
    • 在您的情况下,您必须覆盖 get_serializer_class() 方法。
    • 附带说明,如果对象实现了__getitem__() 函数(例如,列表、元组、字典和字符串),则它是可下标的。 request 对象不是字典,我们无法使用 ['id'] 访问变量。我们需要使用 . 运算符。此外,id 不会作为属性出现在 request 对象上。
    【解决方案2】:

    您可以访问self.instance正在编辑的对象的id

    来自 Accessing the initial data and instance: 上的 DRF 序列化程序文档

    将初始对象或查询集传递给序列化程序实例时, 该对象将以.instance 的形式提供。如果没有初始对象 传递,则.instance 属性将为None

    由于您使用的是HyperLinkedModelSerializer,因此在PUT 请求作为序列化程序上设置的instance 属性的情况下,您将可以访问正在编辑的对象。您可以使用此instance 属性通过执行self.instance.id 访问正在编辑的对象的id

    您可以在validate() 函数中编写验证逻辑,然后在变量object_id 中获取对象ID。这不会影响创建请求,因为instance 不会在序列化程序上设置。

    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
    

    另一种访问对象 ID 的方法是从序列化程序 context 字典中的 view 对象访问 kwargs

    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' 
    

    【讨论】:

    • 出于好奇:你从哪里知道的?文档是否说明了这个anywhere?我可以发誓我阅读了整个文档两次搜索这个。
    • 我遇到了类似的问题,然后不得不查看 DRF 的源代码以了解对象是否被设置为序列化程序的变量。在 DRF 序列化程序文档中也略微提到了这一点。我已经用那个页面链接更新了ans。我认为查看 DRF 的源代码以及文档会更好。 :)
    • self.instance 获取我们需要的所有值!
    猜你喜欢
    • 1970-01-01
    • 2015-12-10
    • 1970-01-01
    • 2021-09-09
    • 2018-11-25
    • 1970-01-01
    • 2019-01-01
    • 2015-12-16
    • 1970-01-01
    相关资源
    最近更新 更多