问题描述:

I can not figure out why a clean_field() method is not being called for an inline form that is updated on an admin view. The code I have seems straight-forward (see synopsis below).

When I modify the Primary form through admin interface (http://admin/..../primary/1/), as expected, I see:

  • Admin.PrimaryAdminForm.clean_myfield() called
  • Admin.PrimaryAdminForm.clean() called
  • Model.Primary.clean() called

However, when I modify the Primary as seen as an inline on the Admin view of Membership (http://admin/..../membership/1/), I only see:

  • Model.Primary.clean() called

I have tried placing the "def clean_myfield(self):" method in the following locations but can not see it get executed from the Membership inlined Primary form:

  • Model.Primary.clean_myfield
  • Admin.PrimaryAdmin.clean_myfield
  • Admin.PrimaryAdminForm.clean_myfield
  • Admin.PrimaryAdminInline.clean_myfield

Is there somewhere else this clean_myfield code should be placed?

I have read (and reread) the Django docs on [forms and field validation][docs.djangoproject.com/en/dev/ref/forms/validation/#form-and-field-validation] which gives a great coverage, but there's nothing on inline validation. I've also read docs.djangoproject.com/en/dev/ref/contrib/admin/#adding-custom-validation-to-the-admin, but no help for inline specific validation. Is there other documentation on this?

---> Answered by Austin provided a doc reference to: "If not specified" (see his link) , which implies the answer. I added a request to improve the documents on this topic.

After further experimenting I found a workaround by putting code in the Model.Primary.clean() method:

def clean(self):

data = self.myfield

data += "_extra" # not actual cleaning code

self.myfield = data

So the question remains: Why is Model.clean() seem to be the only place to put admin inline form validation and not in a clean_myfield(self) method?

---> Answered by Austin. I needed add form = PrimaryAdminForm to PrimaryInline. With this addition, PrimaryAdminForm.clean_myfield(self) is called when PrimaryInline myfield is updated on Membership form. Code ordering was updated due to the added form reference.

Code synopsis:

No forms.py file -- all models are updated through admin interface

models.py:

class Membership(models.Model):

name = models.CharField( max_length=NAME_LENGTH,

null=True, blank=True, verbose_name="Membership Name Tag",

help_text="Name of membership" )

class Primary(models.Model):

user = models.OneToOneField(User, verbose_name="User Name")

membership = models.OneToOneField(Membership, verbose_name="Membership Name")

myfield = models.CharField("My Field", max_length=20, null=True, blank=True)

# clean method altered as in Update comment

# Why must this be here? Why not in clean_myfield(self)

def clean(self):

data = self.myfield

data += "_extra" # not actual cleaning code

self.myfield = data

admin.py:

class MembershipAdminForm(ModelForm):

class Meta:

model = Membership

class PrimaryAdminForm(ModelForm):

class Meta:

model = Primary

def clean_myfield(self):

data = self.cleaned_data['myfield']

data += "_extra" # not actual cleaning code

return unicode(data)

def clean(self):

cleaned_data = super(PrimaryAdminForm, self).clean()

# not actual cleaning code

return cleaned_data

# EDIT2: Moved PrimaryInline so it's defined after PrimaryAdminForm

class PrimaryInline(admin.StackedInline):

model = Primary

form = PrimaryAdminForm #EDIT2 as recommended by Austin

raw_id_fields = ['user']

verbose_name_plural = 'Primary Member'

fieldsets = ((None, {'classes': ('mbship', ),

'fields': ('user', 'myfield')}), )

class MembershipAdmin(admin.ModelAdmin):

form = MembershipAdminForm

# inlines

inlines = [PrimaryInline, ]

fieldsets = ((None, {'classes': ('mbship',),

'fields': ('name'), }), )

class PrimaryAdmin(admin.ModelAdmin):

form = PrimaryAdminForm

list_display = ('__unicode__', 'user', 'status', 'date_used' )

search_fields = ['user__first_name', 'user__last_name', 'user__email']

fieldsets = ((None, {'classes': ('mbship',),

'fields': ('user', 'membership', 'myfield'), }), )

def clean_myfield(self):

data = self.cleaned_data['myfield']

data += "_extra" # not actual cleaning code

return unicode(data)

网友答案:

Validation occurs on ModelForm objects, not ModelAdmin objects. If you want to override any clean methods then you have to create your own ModelForm descendent for each required model.

In your example, the PrimaryInline class does not specify a form. If not specified, the form used will be a ModelForm, which doesn't have any of your custom clean methods.

Try this:

class PrimaryInline(admin.StackedInline):
    # ... existing code ...
    form = PrimaryAdminForm

This will now use your custom PrimaryAdminForm with associated clean() methods.

相关阅读:
Top