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

时间:2017-05-08 16:44:03

标签: python django serialization django-rest-framework

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

此外,用户可以稍后使用PUTPATCH请求修改模型实例到RetrieveUpdateDestroyAPIView端点(使用相同的序列化程序)。我不希望用户此时能够修改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')

这允许用户使用RRset序列化程序列出和创建RRsetsSerializer个对象(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. 我需要修改什么才能让序列化程序从视图domain参数中获取name名称?
  2. 序列化程序的read_only_fields设置可防止用户稍后修改domain字段。但是,我不确定此设置是否以某种方式与序列化程序交互尝试设置默认值(即使设置了只读,序列化程序是否可以写入默认值)?
  3. 总结:我正在寻找的是“基于视图参数的默认值的一次写入字段”。

1 个答案:

答案 0 :(得分:0)

我认为您正在寻找HiddenField

组合的CreateOnlyDefault
  

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()))