Opened 13 years ago
Closed 11 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 , 13 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 , 13 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 , 12 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 , 12 years ago
Attachment: | Screen Shot 2012-07-15 at 21.59.02.png added |
---|
comment:6 by , 12 years ago
The function name formfield_for_choice_field
suggests that you are changing the form field, not the database field which is exactly what happens. The form field choices are updated, the model field choices are not, hence validation (on the model level) fails.
If you want flexible choices, define a CharField
in your model without any choices
argument. Create a form where you overwrite the widget for that CharField
with a forms.Select
. Then use the formfield_for_dbfield
function (not the formfield_for_choice_field
since it's not a choice field in the database model) and fill the kwargs['widget'].choices
with your list of choices.
Example:
# models.py from django.db import models1 class Variable(models.Model): name = models.CharField(max_length=3) # admin.py from django import forms from django.contrib import admin from .models import Variable class VariableForm(forms.ModelForm): class Meta: model = Variable widgets = { 'name': forms.Select(), } class VariableAdmin(admin.ModelAdmin): form = VariableForm def formfield_for_dbfield(self, db_field, **kwargs): if db_field.name == "name": kwargs['widget'].choices = ( ('quux', 'quux'), ('quuux', 'quuux'), ) return super(VariableAdmin, self).formfield_for_dbfield(db_field, **kwargs) admin.site.register(Variable, VariableAdmin)
comment:7 by , 11 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 , 11 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
any workaround for this issue ?