There's absolutely no clean way to allow a field to be created & read but not updated #8606
Replies: 3 comments
-
@Ou7law007 I don't have time to test this unfortunately but this is the best solution I can come up with. It requires a small amount of customization in the form of mixin class(es). Make a custom serializer/mixin which adds a class UpdateMixin(serializers.ModelSerializer):
def get_extra_kwargs(self):
kwargs = super().get_extra_kwargs()
no_update_fields = getattr(self.Meta, "no_update_fields", None)
if self.instance and no_update_fields:
for field in no_update_fields:
kwargs.setdefault(field, {})
kwargs[field]["read_only"] = True
return kwargs
class PersonSerializer(UpdateMixin, serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField()
blood_type = serializers.CharField()
class Meta:
model = Person
fields = ["id", "name", "blood_type"]
read_only_fields = ["id"]
no_update_fields = ["blood_type"] One caveat: DRF implements OPTIONS by examining the serializer class. It does NOT retrieve a model instance (see: You can create a view mixin which patches the |
Beta Was this translation helpful? Give feedback.
-
Second this. |
Beta Was this translation helpful? Give feedback.
-
update here, sometimes we just need to "create once and save it, prevent the all updates" rule. It shouldn't be providing by workarounds... |
Beta Was this translation helpful? Give feedback.
-
First of all, I would like to be proven wrong, so please go ahead!
You can make a field
read only
and you can make a fieldupdate & create only
and you can make a fieldupdate & create & read
but you cannot make a fieldread & create only
, basically, prevent modification, you need a whole other serializer for that.Making the field
editable=False
on the model level only makes itread only
meaning it'll be ignored on create operations, although the name impliescreate
as well!At this point, there's no other option but to pollute the serializer by changing the fields dynamically which would break so many things including HTTP OPTIONS and also the Django REST framework helper page, e.g. it would visually show a field to modify an attribute when in fact this attribute is not modifiable when it's actually not because the serializer will dynamically make it read only once it finds out it's being used to update an instance, here, I'm talking about overriding
.update
.Any solution that involves passing context or any information from the view such as
action
is also not considered clean, here I'm talking about overriding other methods such asget_fields
or the ini/constructor.Well, now, it's literally impossible!
The best I could do is inheritance to reduce code duplication between serializers but again, 50 models * (say) 3 serializers is just a massive amount of time and effort to just change an attribute of a single field.
Please consider this part as well:
What made it even 1000 times more difficult is that in my case, I had some nest serializations where even the nested serializer needs to have
read & create
but notwrite
, and obviously, rest_framework doesn't support nested serializers'update | write
by default hence... I'm losing braincells.Please take everything I said with a grain of salt.
Thanks to everyone who wrote any single piece of code for
django-rest-framework
, a lot of people have not had the chance to express their gratefulness, on their behalf, thank you.Beta Was this translation helpful? Give feedback.
All reactions