Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Allowing Edit to editable=False Fields in Django Admin

DRF will use the editable=False on a field to default the Serializer to read-only. This is a very helpful / safe default that I take advantage of (ie I won't forget to set the Serializer to read-only). That being said once I have set editable=False is there any way to then force the Django admin to allow editing one of those fields?

Presumably the admin is a super user and I do want him to be able to change the fields value but fore safety I want the default Serializer logic to be read only.

UPDATE

I don't actually need to be able to edit the field as much as "set-it" when I create the object.

like image 984
Alex Rothberg Avatar asked Oct 26 '25 10:10

Alex Rothberg


1 Answers

You are going about this the wrong way.

Your models should be the most pure implementation of the things you are modelling. If something about a model is fixed (for example a creation date) it shouldn't be editable in the model, if its mutable, then leave as editable in the model.

Otherwise, in the future you (or someone else) might be stuck wondering why a field which is set to editable=False is some how being changed. Especially as the documentation states:

If False, the field will not be displayed in the admin or any other ModelForm. They are also skipped during model validation.

If you have one view in which it shouldn't be editable (such as in the API), then override it there.

If you have multiple serilaizers for a model, instead make an abstract serializer with a read_only_fields set and then subclass that. For example:

class AbstractFooSerializer(serializers.ModelSerializer):
    class Meta:
        model = Foo
        read_only_fields = ('bar',)


class MainFooSerializer(AbstractFooSerializer):
    pass

class DifferentFooSerializer(AbstractFooSerializer):
    pass

If you really, really want to use editable=False, but allow the item to be edited in the Admin site only on creation you have an up hill battle.

Probably the best approach would be to reimplement the AdminForm you are using for the Admin

So instead of:

class FooAdmin(admin.ModelAdmin):

Use:

class FooAdmin(admin.ModelAdmin):
    form = MySpecialForm

Then declare the form:

class MySpecialForm(forms.Model):
    def __init__(self, *args, **kwargs):
        self.is_new = False
        if kwargs.get('instance',None) is None:
            # There is no instance, thus its a new item
            self.is_new = True
            self.fields['one_time_field'] = forms.CharField() # Or what have you.
        super(MySpecialForm, self).__init__(*args, **kwargs)

    def save(self, commit=True):
         instance = super(MySpecialForm, self).save(commit)
         if self.is_new:
             instance.your_one_time_only_field = self.one_time_field
             instance.save()
         return instance

Note: you will need to manually add a field and save each readonly field that you want to do this for. This may or may not be 100% functional.


Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!