我正在使用Django 2.x
和Django REST Framework
。
我有一个以contact
作为外键的模型
class AmountGiven(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
contact = models.ForeignKey(Contact, on_delete=models.PROTECT)
amount = models.FloatField(help_text='Amount given to the contact')
given_date = models.DateField(default=timezone.now)
created = models.DateTimeField(auto_now=True)
和类似的序列化器
class AmountGivenSerializer(serializers.ModelSerializer):
mode_of_payment = serializers.PrimaryKeyRelatedField(queryset=ModeOfPayment.objects.all())
contact_detail = ContactSerializer(source='contact', read_only=True)
contact = serializers.PrimaryKeyRelatedField(queryset=Contact.objects.all())
class Meta:
model = AmountGiven
depth = 1
fields = (
'id', 'contact', 'contact_detail', 'amount', 'given_date', 'created'
)
创建新记录时需要 contact
字段。但是我不希望contact
一旦创建就被修改。
但是当我仅使用amount
方法发送PUT
时,它说
{
"contact": [
"This field is required."
]
}
当我使用PATCH
方法时,它可以正常工作,但如果为contact
传递其他值,它也将更新contact
。
我想在更新现有记录时将contact
字段设为not-required
。即使已通过,也请使用较早的版本,而不要设置新数据。
审判2
我尝试将请求中的contact
字段重写为先前存储的值,以防万一如果更改的contact
被传递或没有contact
被传递,它将保存较早的一个。
因此,在视图集中添加函数
def update(self, request, *args, **kwargs):
obj = self.get_object()
request.data['contact'] = obj.contact_id
return super().update(request, *args, **kwargs)
但这给了错误
This QueryDict instance is immutable
答案 0 :(得分:1)
使用串行器的__init__
方法在更新对象时读取它:
class AmountGivenSerializer(serializers.ModelSerializer):
def __init__(self, *args, **kwargs):
"""If object is being updated don't allow contact to be changed."""
super().__init__(*args, **kwargs)
if self.instance is not None:
self.fields.get('parent').read_only = True
# self.fields.pop('parent') # or remove the field
mode_of_payment = serializers.PrimaryKeyRelatedField(queryset=ModeOfPayment.objects.all())
contact_detail = ContactSerializer(source='contact', read_only=True)
contact = serializers.PrimaryKeyRelatedField(queryset=Contact.objects.all())
class Meta:
model = AmountGiven
depth = 1
fields = (
'id', 'contact', 'contact_detail', 'amount', 'given_date', 'created'
)
不建议使用self.context['view'].action
,因为在DRF之外使用串行器时,它将不起作用。在常规Django视图中。最好使用self.instance
,因为它在每种情况下都可以使用。
答案 1 :(得分:0)
如果您的视图集是ModelViewSet
,则可以覆盖perform_update
钩子(因为ModelViewSet
继承自GenericAPIView
(请看“保存和删除钩子”))您可以使用序列化程序的instance
字段来访问旧联系人:
class MyViewSet(viewsets.ModelViewSet):
# ... other stuff
def perform_update(self, serializer):
serializer.save(contact=serializer.instance.contact)
因此您将必须提供一个联系人,但是无论您提供哪个联系人,它在更新时将始终使用旧的已保存联系人。