在 Django 序列化程序中,从上下文(或请求数据)获取默认字段值

Pet*_*sen 3 python django serialization django-rest-framework

我将 Django 与 REST Framework 结合使用。在序列化器中,我想根据视图或请求(request.data['type'])参数分配字段值,因此我需要上下文中的视图/请求。

我成功了,但只是以一种麻烦的方式,我正在寻找简化代码的方法。这是成功的方法(省略不相关的字段):

class TypeDefault(object):
    def set_context(self, serializer_field):
        view = serializer_field.context['view'] # or context['request']

        self.type = view.kwargs['type'].upper()

    def __call__(self):
        return self.type


class RRsetSerializer(serializers.ModelSerializer):
    type = serializers.CharField(read_only=True, default=serializers.CreateOnlyDefault(TypeDefault()))

    class Meta:
        model = RRset
        fields = ('type',)
        read_only_fields = ('type',)
Run Code Online (Sandbox Code Playgroud)

为了简化事情,我尝试删除该类TypeDefault,并将type序列化器字段替换为

    type = serializers.SerializerMethodField()

    def get_type(self, obj):
        return self.context.get('view').kwargs['type'].upper() # also tried self._context
Run Code Online (Sandbox Code Playgroud)

然而,context.get('view')回报None。我不确定为什么视图上下文在这里不可用。我的印象是,应该可以获得所需的功能,而无需求助于额外的类。

作为奖励,最好在字段声明本身中指定默认值,例如

    type = serializers.CharField(default=self.context.get('view').kwargs['type'].upper())
Run Code Online (Sandbox Code Playgroud)

然而,self这里没有定义,我不确定正确的方法是什么。


另外,我感兴趣的是从视图或请求数据检索信息是否有任何差异。CreateOnlyDefault虽然上下文方法应该适用于两者,但当从请求数据获取值时,也许有一种更简单的方法来获取功能,因为序列化器无论如何都会处理请求数据。


编辑:根据 Geotob 的请求,以下是调用序列化器的视图的代码:

class RRsetsDetail(generics.ListCreateAPIView):
    serializer_class = RRsetSerializer
    # permission_classes = ... # some permission constraints

    def get_queryset(self):
        name = self.kwargs['name']
        type = self.kwargs.get('type')

        # Note in the following that the RRset model has a `domain` foreign-key field which is referenced here. It is irrelevant for the current problem though.
        if type is not None:
            return RRset.objects.filter(domain__name=name, domain__owner=self.request.user.pk, type=type)
        else:
            return RRset.objects.filter(domain__name=name, domain__owner=self.request.user.pk)
Run Code Online (Sandbox Code Playgroud)

在 中urls.py,我有(除其他外):

url(r'^domains/(?P<name>[a-zA-Z\.\-_0-9]+)/rrsets/$', RRsetsDetail.as_view(), name='rrsets'),
url(r'^domains/(?P<name>[a-zA-Z\.\-_0-9]+)/rrsets/(?P<type>[A-Z]+)/$', RRsetsDetail.as_view(), name='rrsets-type'),
Run Code Online (Sandbox Code Playgroud)

Mic*_*oni 5

SerializerMethodField是一个只读字段,所以我认为除非您设置默认值,否则它不会起作用......并且您又回到了与CharField.

简单地说,你可以摆脱的东西serializers.CreateOnlyDefault

class RRsetSerializer(serializers.ModelSerializer):
    type = serializers.CharField(read_only=True, default=TypeDefault())
Run Code Online (Sandbox Code Playgroud)

如果你想要更有活力的东西,我只能想到这样的东西:

class FromContext(object):
    def __init__(self, value_fn):
        self.value_fn = value_fn

    def set_context(self, serializer_field):
        self.value = self.value_fn(serializer_field.context)

    def __call__(self):
        return self.value


class RRsetSerializer(serializers.ModelSerializer):
    type = serializers.CharField(read_only=True,
            default=FromContext(lambda context: context.get('view').kwargs['type'].upper()))
Run Code Online (Sandbox Code Playgroud)

FromContext在实例化期间采用一个函数,该函数将用于从上下文中检索您想要的值。