Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django admin - remove field if editing an object

I have a model which is accessible through the Django admin area, something like the following:

# model
class Foo(models.Model):
    field_a = models.CharField(max_length=100)
    field_b = models.CharField(max_length=100)

# admin.py
class FooAdmin(admin.ModelAdmin):
    pass

Let's say that I want to show field_a and field_b if the user is adding an object, but only field_a if the user is editing an object. Is there a simple way to do this, perhaps using the fields attribute?

If if comes to it, I could hack a JavaScript solution, but it doesn't feel right to do that at all!

like image 800
John McCollum Avatar asked May 19 '10 15:05

John McCollum


1 Answers

You can create a custom ModelForm for the admin to drop the field in the __init__

class FooForm(forms.ModelForm):
    class Meta(object):
        model = Foo

    def __init__(self, *args, **kwargs):
        super(FooForm, self).__init__(*args, **kwargs)
        if self.instance and self.instance.pk:
            # Since the pk is set this is not a new instance
            del self.fields['field_b']

class FooAdmin(admin.ModelAdmin):
    form = FooForm

EDIT: Taking a hint from John's comment about making the field read-only, you could make this a hidden field and override the clean to ensure the value doesn't change.

class FooForm(forms.ModelForm):
    class Meta(object):
        model = Foo

    def __init__(self, *args, **kwargs):
        super(FooForm, self).__init__(*args, **kwargs)
        if self.instance and self.instance.pk:
            # Since the pk is set this is not a new instance
            self.fields['field_b'].widget = forms.HiddenInput()

    def clean_field_b(self):
        if self.instance and self.instance.pk:
            return self.instance.field_b
        else:
            return self.cleaned_data['field_b']  
like image 192
Mark Lavin Avatar answered Oct 06 '22 01:10

Mark Lavin