#25559 closed Uncategorized (wontfix)
Conditional admin inline causes ValidationError
Reported by: | Zach Borboa | Owned by: | nobody |
---|---|---|---|
Component: | contrib.admin | Version: | 1.8 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
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
.
- Add a new student. Specify a name ("Alice") and click the Save and continue editing button.
- Now click the + to add a Team. Specify a team name ("Team A") and click the Save button.
- 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.
# 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)
# 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)
Change History (4)
comment:1 by , 9 years ago
comment:2 by , 9 years ago
Component: | Uncategorized → contrib.admin |
---|---|
Resolution: | → wontfix |
Status: | new → closed |
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.
comment:3 by , 9 years ago
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:
# 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)
comment:4 by , 9 years ago
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.
Please see 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.