4

I have a field (slug) that is "required" in the model, but want to change the field in the ModelAdmin class to be optional. If the user doesn't fill it in, it is automatically filled in by another field (name).

class SomeModel(model.Model):
  name = model.CharField(max_length=255)
  slug = model.SlugField(unique=True, max_length=255)

I tried to do this various ways, such as overriding get_form() within ModelAdmin or using the ModelForm class and specifying the form specifically.

class SomeModelAdmin(admin.ModelAdmin):
    def get_form(self, request, obj=None, **kwargs):
        form = super(self.__class__, self).get_form(request, obj, **kwargs)
        form.slug.required = False
        return form

However, neither solution worked for me. Beyond manually creating the form, is there any other quicker solution?

I have a lot of these forms, and doing it by hand might be tedious and hard to maintain.

GoogleDroid
  • 41
  • 1
  • 2

3 Answers3

5

Found this page through Google when wrestling with the same problem myself. The following will also work in the ModelAdmin:

def get_form(self, *args, **kwargs):
    form = super(SomeModelAdmin, self).get_form(*args, **kwargs)
    form.base_fields['slug'].required = False
    return form

Subsequent forms created from the updated ModelFormMetaclass will have the slug field unrequired.

This works better in my situation, where I have only a single class in which I need to unrequire the field, and don't need to do any data transformation on save. GoogleDroid's solution is better if you have a lot of classes, or where the data transformations are necessary.

Eric P
  • 4,587
  • 6
  • 24
  • 19
1

In your get_form method, form.fields['slug'].required should work.

But the proper way to do this is to simply provide a custom ModelForm.

class SomeModelForm(forms.ModelForm):
    slug = forms.CharField(required=False)

class SomeModelAdmin(admin.ModelAdmin):
    form = SomeModelForm

Incidentally, please don't do super(self.__class__, self). You should always explicitly name the current class when using super, otherwise any subclass that inherits from yours and in turn calls super will break.

Edit form.fields, not forms.fields.

By saying self.__class__, you are explicitly stopping Python from working out the inheritance - because it always refers to the concrete class - ie the bottom of the inheritance tree. But if your method is the middle of that tree, then referring to the concrete class in super is wrong - because you want it to call the next level up from where you are, not one up from the bottom. That's why you should always name the class you're in - in this case, super(SomeModelAdmin, self).

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • I got an `AttributeError` signifying fields as not a valid attribute using `forms.fields['slug'].required`. Providing a customized form is something I'm trying to avoid due to the amount of work involved, because of the number of models I have. Also, I'm not entirely sure why `super(self.__class__, self)` would break if it is sub-classed? Shouldn't Python be able to figure out based on the scope? Thank you for looking into this. – GoogleDroid May 21 '11 at 19:28
  • Thanks again! That was a typo on my part here, but it is correct in my code, but still not working. I discovered the type of the form being return from `get_form` is `django.forms.models.ModelFormMetaclass`. `dir(form)` didn't show the fields attribute either. – GoogleDroid May 21 '11 at 21:01
1

I just wanted to report back in case others might find this useful.

I was never able to in get_form method do form.fields['slug'].required and never figured out why. However, I solved my problem by creating a new form inheriting from ModelForm.

I had to override init() to set self.fields['slug'].required = False after calling the parent constructor, then override clean_slug() to modify the slug field content if required by accessing self.data['slug'].

Hope this helps someone

GoogleDroid
  • 185
  • 1
  • 6