Opened 14 years ago
Closed 12 years ago
#18168 closed Bug (fixed)
formfield_for_choice_field() doesn't validate choices updated in method
| Reported by: | Owned by: | nobody | |
|---|---|---|---|
| Component: | contrib.admin | Version: | 1.3 |
| Severity: | Normal | Keywords: | admin, inlines |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Having field declared in model:
element = models.CharField(max_length=500, verbose_name=_('admin element'), choices=(('foo', 'bar'),))
and that function in admin:
class AdminModuleElementInline(admin.StackedInline):
model = AdminModuleElement
def formfield_for_choice_field(self, db_field, request=None, **kwargs):
if db_field.name == 'element':
kwargs['choices'] = (
('accepted', 'Accepted'),
('denied', 'Denied'),
)
return db_field.formfield(**kwargs)
when I try to save it I get an error:
Value u'accepted' is not a valid choice.
So it updates the list, but validator checks the choices declared in model.
Attachments (1)
Change History (9)
comment:1 by , 14 years ago
| Keywords: | admin inlines added |
|---|---|
| Summary: | formfield_for_choice_field() doesn't update choices declared in model → formfield_for_choice_field() doesn't validate choices declared in model |
comment:2 by , 14 years ago
| Summary: | formfield_for_choice_field() doesn't validate choices declared in model → formfield_for_choice_field() doesn't validate choices updated in method |
|---|
comment:3 by , 13 years ago
comment:5 by , 13 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
There is no traceback -- the validation error is displayed in the admin.
The reporter's example uses inlines. I could reproduce the issue with the following code. Screenshot attached.
# models.py
from django.db import models1
class Variable(models.Model):
NAME_CHOICES = (
('foo', 'foo'),
('bar', 'bar'),
('baz', 'baz'),
)
name = models.CharField(max_length=3, choices=NAME_CHOICES)
# admin.py
from django.contrib import admin
from .models import Variable
class VariableAdmin(admin.ModelAdmin):
def formfield_for_choice_field(self, db_field, request, **kwargs):
if db_field.name == "name":
kwargs['choices'] = (
('quux', 'quux'),
('quuux', 'quuux'),
)
return super(VariableAdmin, self).formfield_for_choice_field(db_field, request, **kwargs)
admin.site.register(Variable, VariableAdmin)
I don't think it makes sense to allow in the form values that aren't allowed by the model. If I understand correctly this method can only be used to restrict changes, not to extend them. If that's true, it should be mentioned in the documentation of formfield_for_choice_field.
by , 13 years ago
| Attachment: | Screen Shot 2012-07-15 at 21.59.02.png added |
|---|
comment:6 by , 13 years ago
This would limit the flexibility of the formfield_for_choice_field function quite a bit, which I find unfortunate.
Adding arbitrary values to the choices is not wrong, since they are added to the "choices" and therefore not incorrect as a choice. It would be different if you change choices through some Javascript and let Django accept it.
I don't think it makes sense to allow in the form values that aren't allowed by the model
The choice fields (often on top of database CharField or IntegerField) do no enforce any referential integrity anyway. One can simply remove one of the choices in the code and the database nor the Django admin (for reading at least) would complain, which is the correct behavior.
As a workaround, you overriding YourForm.__init___ and use your custom form in the ModelAdmin which adjusts your choices (depends a bit on what you need to base your choices on).
comment:7 by , 12 years ago
hitting an unrelated issue in some of this same code, and figured I'd address this. The best fix for now is to clarify that model choices and their validation always trump form choices.
There are a number of places where this can cause a trip up, but I'm going to go with a fix for this as a doc note.
comment:8 by , 12 years ago
| Resolution: | → fixed |
|---|---|
| Status: | new → closed |
any workaround for this issue ?