使用Django REST Framework,我想允许用户通过ListCreateAPIView
(通过POST
)创建和保存Django模型的实例。其中一个字段(称为domain
的外键字段)应根据urls.py
中定义的视图参数确定。
此外,用户可以稍后使用PUT
或PATCH
请求修改模型实例到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',)
问题:
domain
参数中获取name
名称?read_only_fields
设置可防止用户稍后修改domain
字段。但是,我不确定此设置是否以某种方式与序列化程序交互尝试设置默认值(即使设置了只读,序列化程序是否可以写入默认值)?总结:我正在寻找的是“基于视图参数的默认值的一次写入字段”。
答案 0 :(得分:0)
我认为您正在寻找HiddenField
组合的CreateOnlyDefaultHiddenField
一个字段类,它不根据用户输入获取值,而是从默认值或可调用值中获取其值。
<强> 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()))