views:

188

answers:

1

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!

+2  A: 

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']  
Mark Lavin
Thanks for your answer! It looks like it should work, but I get a TemplateSyntaxError when editing an object - "Key 'field_b' not found in Form". Any idea how that might be fixed?
John McCollum
I got round this by changing the field to a CharField (it was initially a select list) and marking it as readonly - this is fine for my purposes. Something like: self.fields['field_b'] = forms.CharField(initial="initial value"); self.fields['field_b'].widget.attrs['readonly'] = True
John McCollum
Crap I forgot that the admin uses the ModelAdmin fieldset rather than the fields on the model to generate the template but I'm glad you got it worked out.
Mark Lavin
No worries. I played with swapping it for a hidden field too, but it leaves the label to the left, which is a little ugly. :) Thanks again for your help!
John McCollum