使用Django REST框架,如何避免在序列化器和视图中获取对象?

时间:2016-03-15 21:27:34

标签: django django-rest-framework

假设我的一个POSTed DRF API参数是一个允许我识别对象的字符串。然后,我的序列化程序使用此字段来验证字符串(以及其他一些POSTed参数)并获取底层对象(作为验证的最后部分)。所以,在validate()的末尾,我已经在我的视图中查找了我需要使用的对象,但我无法弄清楚如何在视图中访问此对象。如果我在data['my_object'] = my_object的末尾设置了validate(),那么在我的视图中serializer.is_valid()返回后,它最终只是我的对象的名称。

如何将序列化程序中的对象“传递”回视图? (或者,如果有理由不这样做,那么避免在数据库中查找同一个对象两次的最佳做法是什么?)

# serializer
class MySerializer(serializers.Serializer):
    my_string_param = serializers.CharField()
    another_param = serializers.CharField()
    ...
    def validate(self, data):
        # validate data['my_string_param'] and fetch my_object
        try:
            my_object = MyModel.objects.get(
                field1=data['my_string_param'], field2=data['another_param'])
        except MyModel.DoesNotExist:
            raise ValidationError('Please check your params and try again.')
        data['my_object'] = my_object  # doesn't work: is a string when later accessed in the view 
        return data

# view
class MyView(APIView):
    ...
    def post(self, request, format=None):
        serializer = MySerializer(data=request.data)
        if serializer.is_valid():
            # don't want to fetch from db again
            # my_object = MyModel.objects.get(field1=serializer.data['my_string_param'], field2=serializer.data['another_param'])

            # would like to reuse already fetched object, but it's just its str name
            my_object = serializer.data['my_object']

            # do stuff with my_object and return
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

1 个答案:

答案 0 :(得分:1)

您可以将获取的对象设置为序列化程序属性,然后在视图中访问此属性。这样做可以避免在视图中出现额外的查询。

# serializer
class MySerializer(serializers.Serializer):
    my_string_param = serializers.CharField()
    another_param = serializers.CharField()
    ...
    def validate(self, data):
        # validate data['my_string_param'] and fetch my_object
        try:
            # set the object as an attribute
            self.my_object = MyModel.objects.get( 
                field1=data['my_string_param'], field2=data['another_param'])
        except MyModel.DoesNotExist:
            raise ValidationError('Please check your params and try again.')
        return data

# view
class MyView(APIView):
    ...
    def post(self, request, format=None):
        serializer = MySerializer(data=request.data)
        if serializer.is_valid():            
            my_object = serializer.my_object # access the already retrieved object 

            # do stuff with my_object and return
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)