我只是写场和Widget子类,它们可以解决这个特殊的问题,并且可以和JS自动完成一起使用,并且可以重用。不过,它需要比解决方案更多的工作,而且我不确定是否要使用我的解决方案。无论哪种方式 - 我希望我会得到一些upvotes - 我花了相当长的一段时间和精力写这...
相反的定义就像你你的ModelForm没有与clean_
搞乱我建议这样的事情:
class SongForm(forms.ModelForm):
artist = CustomModelChoiceField(queryset = Artist.objects.all(), query_field = "name")
class Meta:
model = Song
现在,CustomModelChoiceField(我想不出更好的名称)是ModelChoiceField的子类,这很好,因为我们可以使用queryset
参数来缩小可接受的选择范围。如果widget
参数不存在(如上所述),则会使用此字段的默认值(稍后会详细介绍)。 query_field
是可选的,默认为"pk"
。所以,这里是域代码:
class CustomModelChoiceField(forms.ModelChoiceField):
def __init__(self, queryset, query_field = "pk", **kwargs):
if "widget" not in kwargs:
kwargs["widget"] = ModelTextInput(model_class = queryset.model, query_field = query_field)
super(CustomModelChoiceField, self).__init__(queryset, **kwargs)
def to_python(self, value):
try:
int(value)
except:
from django.core.exceptions import ValidationError
raise ValidationError(self.error_messages['invalid_choice'])
return super(CustomModelChoiceField, self).to_python(value)
什么身体__init__
手段是创造CustomModelChoiceField
过程中设置widget = None
给了我们普通ModelChoiceField
(这是非常有益的,而调试...)。现在,实际的工作在ModelTextInput
部件进行:
class ModelTextInput(forms.TextInput):
def __init__(self, model_class, query_field, attrs = None ):
self.model_class = model_class
self.query_field = query_field
super(ModelTextInput, self).__init__(attrs)
def render(self, name, value, attrs = None):
try:
obj = self.model_class.objects.get(pk = value)
value = getattr(obj, self.query_field)
except:
pass
return super(ModelTextInput, self).render(name, value, attrs)
def value_from_datadict(self, data, files, name):
try:
return self.model_class.objects.get(**{ self.query_field : data[name] }).id
except:
return data[name]
它本质的TextInput,就是知道的两个额外的东西 - 这模型它代表哪个属性。 (model_class
应替换为queryset
,以便将实际可能的选择缩小至实际工作状态,稍后我会予以修复)。查看value_from_datadict
的实现,很容易发现为什么to_python
必须被重写 - 它期望值为int
,但不检查它是否为真 - 并仅将值传递给关联的模型,该模型因丑陋的异常而失败。
我测试了这一段时间,它的工作原理 - 你可以指定由形成场会尝试不同的模型领域找到自己的artist
,形状误差处理是由基类自动完成的,不需要编写自定义的clean_
方法每次你想使用类似的功能。
我现在太累了,但我会尽力编辑明天的这篇文章(和代码)。
还没有试过,但看起来很有趣 – juanefren 2010-07-26 23:33:00