在Django中,ChoiceField
或ModelChoiceField
代表Select
小部件中的数据。当对象列表很小时,这很有用。但是,如果对象数量为数千,则管理(对于最终用户)非常困难。
为了消除上述问题,我希望最终用户在文本类型的输入框中手动输入字段值(即通过TextInput
小部件)。
到目前为止,我已经创建了以下代码。由于ModelChoiceField
默认情况下有Select
小部件;即使将窗口小部件更改为TextInput
,其行为也与之前类似。它期望模型对象的pk
或id
值,从而引发错误:
选择有效的选择。这个选择不是可用的选择之一。
但是,我希望最终用户在输入框中输入sku_number
字段,而不是对象的pk
或id
。解决这个问题的正确方法是什么?
models.py
class Product(models.Model):
sku_number = models.CharField(null=False, unique=True)
product_name = models.CharField(null=Flase)
def __str__(self):
return self.sku_number
forms.py
class SkuForm(forms.Form):
sku_number = forms.ModelChoiceField(queryset=Product.objects.all(),
widget=forms.TextInput())
extra_field = forms.CharField(required=True)
注意:我尝试了另一种解决此问题的方法。通过切割对象的数量,仅显示最后10个对象;这样可以确保选择框中没有数千个项目。
queryset=Product.objects.all().order_by('-id')[:10]
如果正确实施,后一种方法将适用于我的特定用例,但其他人可能对前一种方法感兴趣。由于Django生成SQL语句的限制,上述声明进一步引发了错误。
另请注意,即使切换未评估的 QuerySet 会返回另一个未评估的 QuerySet ,也不允许进一步修改它(例如,添加更多过滤器或修改排序),因为这不能很好地转化为SQL,也不会有明确的含义。
来源:Django Docs
答案 0 :(得分:1)
您可以使用表单clean()方法轻松完成此操作。
即
from django.shortcuts import get_object_or_404
class SkuForm(forms.Form):
sku = forms.CharField(required=True)
extra_field = forms.CharField(required=True)
def clean(self):
# If you're on Python 2.x, change super() to super(SkuForm, self)
cleaned_data = super().clean()
sku = cleaned_data['sku']
obj = get_object_or_404(Product, sku_number=sku)
# do sth with the Product
答案 1 :(得分:0)
就我而言,我必须将sku_number
字段更改为Product对象的id
。这必须在clean()
之前完成。如this answer所示,__init__()
应该用于在数据到达clean()
之前对其进行修改。
class SkuForm(forms.Form):
sku_number = forms.ModelChoiceField(queryset=Product.objects.all(),
widget=forms.TextInput())
extra_field = forms.CharField(required=True)
def __init__(self, data=None, *args, **kwargs):
if data is not None:
data = data.copy() # make it mutable
if data['sku_number']:
obj = get_object_or_404(Product, batch_name=data['sku_number'])
data['sku_number'] = obj.id
super(SkuForm, self).__init__(data=data, *args, **kwargs)