管理表单中的django自定义模型字段给出无效选择错误 [英] django custom model field in admin form gives invalid choice error
问题描述
我有以下类用于自定义模型字段:
I have the following class which to be used for a custom model field:
class PaymentGateway(object):
def fullname(self):
return self.__module__ + "." + self.__class__.__name__
def authorize(self):
raise NotImplemented()
def pay(self):
raise NotImplemented()
def __unicode__(self):
return self.fullname()
class DPS(PaymentGateway):
def authorize(self):
pass
def pay(self):
pass
这是我如何编写自定义模型字段:
This is how I am writing the custom model field:
from django.db import models
from django.utils.six import with_metaclass
from django.utils.module_loading import import_by_path
class PaymentGatewayField(with_metaclass(models.SubfieldBase, models.CharField)):
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 255
super(PaymentGatewayField, self).__init__(*args, **kwargs)
def to_python(self, value):
if value and isinstance(value, basestring):
kls = import_by_path(value)
return kls()
return value
def get_prep_value(self, value):
if value and not isinstance(value, basestring):
return value.fullname()
return value
def value_from_object(self, obj):
return self.get_prep_value(getattr(obj, self.attname))
def formfield(self, **kwargs):
defaults = {'form_class': PaymentGatewayFormField}
defaults.update(kwargs)
return super(PaymentGatewayField, self).formfield(**defaults)
class PaymentGatewayFormField(BaseTemporalField):
def to_python(self, value):
if value in self.empty_values:
return None
if isinstance(value, PaymentGateway):
return value
if value and isinstance(value, basestring):
kls = import_by_path(value)
return kls()
return super(PaymentGatewayFormField, self).to_python(value)
这是如何在一个模型中使用的:
And this is how it is used in a model:
class BillingToken(models.Model):
user = models.ForeignKey('User', related_name='billingtokens')
name = models.CharField(max_length=255)
card_number = models.CharField(max_length=255)
expire_on = models.DateField()
token = models.CharField(max_length=255)
payment_gateway = PaymentGatewayField(choices=[('project.contrib.paymentgateways.dps.DPS', 'DPS')])
我已将模型添加到管理员:
I have added the model to admin:
class BillingTokenInline(admin.StackedInline):
model = BillingToken
extra = 0
class UserAdmin(admin.ModelAdmin):
inlines = [BillingTokenInline]
admin.site.register(User, UserAdmin)
所以如果我去编辑ex已经选择了DPS,并且保存,我收到一个无效的选择错误:
So if I go to edit existing user record, which it's billingtoken record has 'DPS' already chosen, and hit save, I get a invalid choice error:
Select a valid choice. project.contrib.paymentgateways.dps.DPS is not one of the available choices.
我试图跟踪django代码,发现错误消息定义在 django.forms.fields.ChoiceField
:
I have tried to trace the django code and found the error message is defined in django.forms.fields.ChoiceField
:
class ChoiceField(Field):
widget = Select
default_error_messages = {
'invalid_choice': _('Select a valid choice. %(value)s is not one of the available choices.'),
}
def __init__(self, choices=(), required=True, widget=None, label=None,
initial=None, help_text='', *args, **kwargs):
super(ChoiceField, self).__init__(required=required, widget=widget, label=label,
initial=initial, help_text=help_text, *args, **kwargs)
self.choices = choices
def __deepcopy__(self, memo):
result = super(ChoiceField, self).__deepcopy__(memo)
result._choices = copy.deepcopy(self._choices, memo)
return result
def _get_choices(self):
return self._choices
def _set_choices(self, value):
# Setting choices also sets the choices on the widget.
# choices can be any iterable, but we call list() on it because
# it will be consumed more than once.
self._choices = self.widget.choices = list(value)
choices = property(_get_choices, _set_choices)
def to_python(self, value):
"Returns a Unicode object."
if value in self.empty_values:
return ''
return smart_text(value)
def validate(self, value):
"""
Validates that the input is in self.choices.
"""
super(ChoiceField, self).validate(value)
if value and not self.valid_value(value):
raise ValidationError(
self.error_messages['invalid_choice'],
code='nvalid_choice',
params={'value': value},
)
def valid_value(self, value):
"Check to see if the provided value is a valid choice"
text_value = force_text(value)
for k, v in self.choices:
if isinstance(v, (list, tuple)):
# This is an optgroup, so look inside the group for options
for k2, v2 in v:
if value == k2 or text_value == force_text(k2):
return True
else:
if value == k or text_value == force_text(k):
return True
return False
但是在将提交ValidationError
行之前添加一些调试语句在这个函数中,这里没有提出异常,但错误信息绝对是从这里引用的。这暗示我在其他地方延伸ChoiceField可能会提高这个异常,我已经尝试了明显的(ChoiceField,TypedChoiceField,MultipleChoiceField,TypedMultipleChoiceField)仍然没有运气。这已经消耗了很多时间,并希望找到一些聪明的线索。
But after putting some debug statements before the raise ValidationError
line in this function, the exception is not raised here, but the error message is definitely referenced from here. Which hints me that somewhere else is extending ChoiceField might be raising this exception, and I have tried the obvious ones (ChoiceField, TypedChoiceField, MultipleChoiceField, TypedMultipleChoiceField) still no luck. This has already consumed a lot of my time and would like to seek some clever clues.
推荐答案
最后,弄清楚它在哪里抛出错误:
Finally, figured out where it is throwing the error:
它在 django / db / models / fields / __ init __。py
第236行
通常是因为第234行:
typically because of line 234:
elif value == option_key:
其中value是一个 PaymentGateway
object和option_key是字符串
Where value is a PaymentGateway
object and option_key is a string
要解决这个问题,我不得不重写干净的方法:
To fix this problem, I had to override the clean method:
def clean(self, value, model_instance):
value = unicode(value)
self.validate(value, model_instance)
self.run_validators(value)
return self.to_python(value)
这篇关于管理表单中的django自定义模型字段给出无效选择错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!