Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在可写序列化程序中将请求/上下文添加到django_Django_Serialization_Django Rest Framework - Fatal编程技术网

在可写序列化程序中将请求/上下文添加到django

在可写序列化程序中将请求/上下文添加到django,django,serialization,django-rest-framework,Django,Serialization,Django Rest Framework,我想将请求上下文添加到Django REST框架中的序列化程序中。特别是对于嵌套序列化程序,我(成功地)尝试使用SerializerMethodField(作为我的解决方案per:)来实现这一点。这是我使用的设置: class VehicleTypeSerializer(RsModelSerializer): class Meta: model = VehicleType class VehicleSerializer(RsModelSerializer):

我想将请求上下文添加到Django REST框架中的序列化程序中。特别是对于嵌套序列化程序,我(成功地)尝试使用SerializerMethodField(作为我的解决方案per:)来实现这一点。这是我使用的设置:

class VehicleTypeSerializer(RsModelSerializer):

    class Meta:
        model = VehicleType


class VehicleSerializer(RsModelSerializer):

    vehicletype = SerializerMethodField()

    class Meta:
        model = Vehicle
        fields = ('vehiclename', 'vehicledescription', 'vehicletype')

    def get_vehicletype(self, obj):
        return self.get_serializermethodfield_data(obj, VehicleType, VehicleTypeSerializer, 'vehicle')


    def get_serializermethodfield_data(self, obj, model_class, serializer_class, filter_field):
        filter = {filter_field: obj}
        objs = model_class.objects.all().filter(**filter)

        # We need the request-context for checking field permissions in the serializer
        s = serializer_class(objs, many=True, context={'request': self.context.get('request')})
        return s.data   
问题:我需要SerializerMethodField将请求上下文传递给嵌套序列化程序(VehicleTypeSerializer) 但现在我一直在处理POST,因为SerializerMethodField是只读的。我无法使用以下内容将对象发布到/api/v1/vehicle:

{
    "vehiclename": "test",
    "vehicledescription": "test"
    "vehicletype": "1" <---- get's ignored since SerializerMethodField is read-only
}

如果需要将上下文传递给序列化程序类。你可以用

您将能够在
SerializerMethodField

class MySerializer(serializer.Serializer)

    field = serializer.SerializerMethodField()

    def get_field(self, obj):
        return self.context.get('my_key')
您可以从视图中调用它:

...
s = MySerializer(data=data, context={'my_key': 'my_value'})
...
编辑:

如果需要在另一个序列化程序类中使用此上下文,请传递给下一个序列化程序中的第一个序列化程序:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    # Make sure that there is a user mapped in the context (we need a user
    # for checking permissions on a field). If there is no user, we set
    # the user to None.
    if not self.context:
        self._context = getattr(self.Meta, 'context', {})
    try:
        self.user = self.context['request'].user
    except (KeyError, AttributeError):
        print('No request')
        self.user = None


def get_fields(self):
    """
    Override get_fields to ensure only fields that are allowed
    by model-field-permissions are returned to the serializer
    :return: Dict with allowed fields
    """

    ret = OrderedDict()
    fields = super().get_fields()

    # If no user is associated with the serializer, return no fields
    if self.user == None:
        return None

    # A superuser bypasses the permissions-check and gets all
    # available fields
    if self.user.is_superuser:
        print_without_test("user is superuser, bypassing permissions")
        return fields

    # Walk through all available fields and check if a user has permission for
    # it. If he does, add them to a return-array. This way all fields that
    # are not allowed to 'read' will be dropped. Note: this is only used
    # for read access. Write access is handled in the views (modelviewsets).
    for f in fields:
        if has_permission(user=self.user, app_label=self.Meta.model._meta.app_label,
                          table=self.Meta.model.__name__.lower(),
                          field=f,
                          permission='read'):
            ret[f] = fields[f]

    return ret
# views.py
...
s = MySerializer(data=data, context={'my_key': 'my_value'})
...

# serializers.py

class MySerializer(serializer.Serializer):
    field = serializer.SerializerMethodField()

    def get_field(self, obj):
        return MySecondSerializer(..., context=self.context)

方法1:重写父序列化程序的
\uuuu init\uuuu()
方法

您可以将上下文添加到父序列化程序的
\uuuu init\uuuu()
方法中的嵌套/子序列化程序中

class RsModelSerializer(serializers.ModelSerializer):

    def __init__(self, *args, **kwargs):
        super(RsModelSerializer, self).__init__(*args, **kwargs)
        request_obj = self.context.get('request') # get the request from parent serializer's context
        # assign request object to nested serializer context
        self.fields['nested_serializer_field'].context['request'] = request_obj 
class SomeParentSerializer(serializers.Serializer):

    some_child = SomeChildSerializer()  # gets initialized here
我们无法在嵌套序列化程序的
\uuuu init\uuuu()
时将上下文传递给嵌套序列化程序,因为它们是在父序列化程序中声明时初始化的

class RsModelSerializer(serializers.ModelSerializer):

    def __init__(self, *args, **kwargs):
        super(RsModelSerializer, self).__init__(*args, **kwargs)
        request_obj = self.context.get('request') # get the request from parent serializer's context
        # assign request object to nested serializer context
        self.fields['nested_serializer_field'].context['request'] = request_obj 
class SomeParentSerializer(serializers.Serializer):

    some_child = SomeChildSerializer()  # gets initialized here
方法2:在子序列化程序绑定到其父序列化程序时传递
上下文

另一个选项是在子/嵌套序列化程序绑定到父序列化程序时添加上下文

class SomeChildSerializer(Serializer):

    def bind(self, field_name, parent):
        super(SomeChildSerializer, self).bind(field_name, parent) # child gets binded to parent
        request_obj = parent.context.get('request') # get the request from parent serializer context
        self.context['request'] = request_obj
在相关票据中引用DRF作者的建议选项:

这应该被视为私有API,而父API 应首选上面列出的
\uuuuu init\uuuu
样式

因此,更好的选择是重写
ParentSerializer
\uuu init\uuu()
方法,并将
上下文
传递给子/嵌套序列化程序


Source:在Github上查看此相关内容。)

这确实是我刚才想出的解决方案(请参见链接),但SerializerMethodField不允许POST请求,它是只读的。如何向具有嵌套字段的序列化程序写入数据并将reuqest上下文传递给它?我想您需要request.data,这是一个字典,您可以在序列化程序调用中通过context attr传递它。或者,请再解释一下。我更新了我的问题,以描述我在一些示例和代码中遇到的问题。您在SerializerMethodField中调用序列化程序,并且需要将上下文传递给该序列化程序?是的,我需要在序列化程序中传递上下文值(上下文={'request':self.context.get('request'))这将添加来自ModelViewSet的请求),以便在request.user没有特定字段的权限时可以在序列化程序中删除字段。这很有效。由于SerializerMethodFields是只读的,因此仅GET除外。当我发布一个值时,它会删除我放在SerializerMethodField中的数据。所以,我必须使用什么样的EqualEvent字段类型来SerializerMethodField,才能a)在其中传递上下文,b)使用它将数据写入API中的POST请求??