记录创建后,Django Rest Framework将字段设置为只读

时间:2018-10-20 09:20:14

标签: django django-rest-framework

我正在使用Django 2.xDjango 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

2 个答案:

答案 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)

因此您将必须提供一个联系人,但是无论您提供哪个联系人,它在更新时将始终使用旧的已保存联系人。