【问题标题】:In a Django serializer, how to set foreign key field based on view argument?在 Django 序列化程序中,如何根据视图参数设置外键字段?
【发布时间】:2017-10-06 18:32:13
【问题描述】:

使用 Django REST 框架,我想允许用户通过ListCreateAPIView(通过POST)创建和保存 Django 模型的实例。其中一个字段(称为domain 的外键字段)应根据urls.py 中定义的视图参数确定。

此外,用户可以稍后使用PUTPATCHRetrieveUpdateDestroyAPIView 端点的请求修改模型实例(使用相同的序列化程序)。我不希望用户此时能够修改domain 字段。

虽然我已经准备好模型和视图/序列化器结构的代码,但我不确定如何告诉序列化器根据视图参数确定domain 字段的值。这是我得到的:

class RRset(models.Model):
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(null=True)
    domain = models.ForeignKey(Domain, on_delete=models.CASCADE, related_name='rrsets')
    subname = models.CharField(max_length=255, blank=True)
    type = models.CharField(max_length=10)

...和一个直截了当的ListCreateAPIView:

class RRsetsDetail(generics.ListCreateAPIView):
    serializer_class = RRsetSerializer
    permission_classes = (permissions.IsAuthenticated,)

    def get_queryset(self):
        name = self.kwargs['name']
        return RRset.objects.filter(domain__name=name, domain__owner=self.request.user.pk)

urls.py 包含以下行:

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

这允许用户使用RRsetsSerializer 序列化程序列出和创建RRset 对象(列出name 字段只是为了完整性,但我认为它在这种情况下并不重要):

class RRsetSerializer(serializers.ModelSerializer):
    name = serializers.SerializerMethodField()

    def get_name(self, obj):
        return '.'.join(filter(None, [obj.subname, obj.domain.name])) + '.' # returns 'subname.name.'

    class Meta:
        model = RRset
        fields = ('created', 'updated', 'domain', 'name', 'type',)
        read_only_fields = ('created', 'updated', 'domain', 'type',)

问题:

  1. 我需要修改哪些内容才能让序列化程序从视图 name 参数中获取 domain 名称?
  2. 序列化程序的read_only_fields 设置可防止用户稍后修改domain 字段。但是,我不确定此设置是否以某种方式与尝试设置默认值的序列化程序交互(即使设置了只读,序列化程序也可以写入默认值)?

总结一下:我正在寻找类似于“具有基于视图参数的默认值的一次性写入字段”。

【问题讨论】:

    标签: python django serialization django-rest-framework


    【解决方案1】:

    我认为您正在寻找HiddenFieldCreateOnlyDefault 的组合

    隐藏字段

    不根据用户输入获取值的字段类,而是从默认值或可调用值中获取值。

    CreateOnlyDefault

    一个默认类,可用于在运行期间仅设置默认参数 创建操作。在更新期间,该字段被省略。

    它接受一个参数,它是默认值或可调用的 应该在创建操作期间使用。

    而且因为您想访问视图,所以不能只使用 callable,而必须使用可以访问上下文数据的 Class-based callable。

    class DomainDefault(object):
        def set_context(self, serializer_field):
            view = serializer_field.context['view']
            request = serializer_field.context['request']
            self.domain = ...#determine the domain based on request+view
    
        def __call__(self):
            return self.domain
    
    
    class RRsetSerializer(serializers.ModelSerializer):
        domain = serializers.HiddenField(default=serializers.CreateOnlyDefault(DomainDefault()))
    

    【讨论】:

    • 谢谢,这看起来很有希望。但是,我收到以下错误(|| 由我表示,表示换行符): Traceback(最近一次调用最后一次):[...] File "/usr/local/lib/python3.5/site-packages/rest_framework /fields.py",第 257 行,在 set_context || self.default.set_context(serializer_field) || TypeError: set_context() missing 1 required positional argument: 'serializer_field' 我不知道出了什么问题。你知道吗?
    • 实例化DomainDefault 类,即使用DomainDefault() 而不仅仅是DomainDefault。会更新答案。
    猜你喜欢
    • 2021-02-13
    • 1970-01-01
    • 1970-01-01
    • 2021-11-16
    • 1970-01-01
    • 2019-01-19
    • 2016-04-10
    • 2020-09-14
    • 1970-01-01
    相关资源
    最近更新 更多