[Django] #25559: Conditional admin inline causes ValidationError

21 views
Skip to first unread message

Django

unread,
Oct 16, 2015, 6:15:53 AM10/16/15
to django-...@googlegroups.com
#25559: Conditional admin inline causes ValidationError
--------------------------------+--------------------
Reporter: zborboa-google | Owner: nobody
Type: Uncategorized | Status: new
Component: Uncategorized | Version: 1.8
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------
Attempting to save an object in the Django admin using a conditional to
show/hide an admin inline causes `ValidationError: ManagementForm data is
missing or has been tampered with`.

1. Add a new student. Specify a name ("Alice") and click the Save and
continue editing button.
2. Now click the + to add a Team. Specify a team name ("Team A") and click
the Save button.
3. Back on the student page with the team now selected, click the Save and
continue editing button.

Result: ValidationError

Expected: Student object to be saved and the inline to now be displayed.

{{{#!python
# myapp/models.py
from django.db import models

class Team(models.Model):
name = models.CharField(max_length=255)

def __unicode__(self):
return self.name

class Category(models.Model):
name = models.CharField(max_length=255)

class Student(models.Model):
name = models.CharField(max_length=255)
team = models.ForeignKey(Team, blank=True, null=True)
categories = models.ManyToManyField(Category, through='CategoryInfo')

class CategoryInfo(models.Model):
category = models.ForeignKey(Category)
student = models.ForeignKey(Student)
score = models.CharField(max_length=255)
}}}

{{{#!python
# myapp/admin.py
from django.contrib import admin

from models import Student
from models import Team

class CategoryInlineAdmin(admin.TabularInline):
model = Student.categories.through

class StudentAdmin(admin.ModelAdmin):
inlines = []
def get_inline_instances(self, request, obj=None):
inlines = self.inlines
# Display inline when the object has been saved and a team has
been selected.
if obj and obj.team:
inlines = [CategoryInlineAdmin,]
return [inline(self.model, self.admin_site) for inline in inlines]

class TeamAdmin(admin.ModelAdmin):
pass

admin.site.register(Student, StudentAdmin)
admin.site.register(Team, TeamAdmin)
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/25559>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Oct 17, 2015, 4:47:12 PM10/17/15
to django-...@googlegroups.com
#25559: Conditional admin inline causes ValidationError
--------------------------------+--------------------------------------

Reporter: zborboa-google | Owner: nobody
Type: Uncategorized | Status: new
Component: Uncategorized | Version: 1.8
Severity: Normal | Resolution:
Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------
Changes (by timgraham):

* needs_better_patch: => 0
* needs_tests: => 0
* needs_docs: => 0


Comment:

Please see
[https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_inline_instances
the note for get_inline_instances() in the documentation], "If you
override this method, make sure that the returned inlines are instances of
the classes defined in inlines or you might encounter a “Bad Request”
error when adding related objects." You need
`inlines=[CategoryInlineAdmin]` in the class body I believe. If that's
correct, we might amend the docs.

--
Ticket URL: <https://code.djangoproject.com/ticket/25559#comment:1>

Django

unread,
Oct 17, 2015, 7:36:09 PM10/17/15
to django-...@googlegroups.com
#25559: Conditional admin inline causes ValidationError
--------------------------------+--------------------------------------
Reporter: zborboa-google | Owner: nobody
Type: Uncategorized | Status: closed
Component: contrib.admin | Version: 1.8
Severity: Normal | Resolution: wontfix
Keywords: | Triage Stage: Unreviewed

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------
Changes (by timgraham):

* status: new => closed
* resolution: => wontfix
* component: Uncategorized => contrib.admin


Comment:

After looking at this a bit closer, I don't see a way that Django could
generally solve it. Possibly you could fix this in your app by using some
JavaScript to insert the necessary formset HTML fields based on whether or
not a team is selected. Feel free to reopen if you have some ideas or a
patch to share.

--
Ticket URL: <https://code.djangoproject.com/ticket/25559#comment:2>

Django

unread,
Oct 29, 2015, 12:57:05 PM10/29/15
to django-...@googlegroups.com
#25559: Conditional admin inline causes ValidationError
--------------------------------+--------------------------------------
Reporter: zborboa-google | Owner: nobody

Type: Uncategorized | Status: closed
Component: contrib.admin | Version: 1.8
Severity: Normal | Resolution: wontfix
Keywords: | Triage Stage: Unreviewed

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------

Comment (by zborboa-google):

Can we document overriding `change_view` is possible to achieve this?

Here's a solution that works. Use `change_view` to conditionally display
the inline. Replace `myapp/admin.py` above with this:

{{{#!python
# myapp/admin.py
from django.contrib import admin

from models import Student
from models import Team

class CategoryInlineAdmin(admin.TabularInline):
model = Student.categories.through

class StudentAdmin(admin.ModelAdmin):
inlines = []

def change_view(self, request, object_id, form_url='',
extra_context=None):


# Display inline when the object has been saved and a team has
been selected.

self.inlines = []
try:
obj = self.model.objects.get(pk=object_id)
except self.model.DoesNotExist:
pass
else:
if obj.team:
self.inlines = [CategoryInlineAdmin,]
return super(StudentAdmin, self).change_view(request, object_id,
form_url, extra_context)

class TeamAdmin(admin.ModelAdmin):
pass

admin.site.register(Student, StudentAdmin)
admin.site.register(Team, TeamAdmin)
}}}

--
Ticket URL: <https://code.djangoproject.com/ticket/25559#comment:3>

Django

unread,
Oct 29, 2015, 1:58:23 PM10/29/15
to django-...@googlegroups.com
#25559: Conditional admin inline causes ValidationError
--------------------------------+--------------------------------------
Reporter: zborboa-google | Owner: nobody

Type: Uncategorized | Status: closed
Component: contrib.admin | Version: 1.8
Severity: Normal | Resolution: wontfix
Keywords: | Triage Stage: Unreviewed

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0

Easy pickings: 0 | UI/UX: 0
--------------------------------+--------------------------------------

Comment (by timgraham):

I'm not sure that modifying `self.inlines` like that is thread safe.

I don't think documenting every way the admin can be customized has a
place in the Django documentation. It's not trivial to maintain examples
and to ensure they continue working in future versions of Django.

--
Ticket URL: <https://code.djangoproject.com/ticket/25559#comment:4>

Reply all
Reply to author
Forward
0 new messages