首页 文章

在Django序列化程序中,如何根据视图参数设置外键字段?

提问于
浏览
4

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

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

虽然我已准备好模型的代码和视图/序列化器结构,但我不知道如何告诉序列化程序根据view参数确定 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',)

问题:

  • 我需要修改什么才能让序列化程序从视图 name 参数中获取 domain 名称?

  • 序列化程序的 read_only_fields 设置可防止用户稍后修改 domain 字段 . 但是,我不确定此设置是否以某种方式与序列化程序交互尝试设置默认值(即使设置了只读,串行器是否可以写入默认值)?

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

1 回答

  • 0

    我想你正在寻找HiddenFieldCreateOnlyDefault的组合

    HiddenField一个字段类,它不根据用户输入获取值,而是从默认值或可调用值中获取其值 . 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()))
    

相关问题