我有2个型号产品和类别 - ManyToMany关系产品类别和自我ForeignKey类别
class Category(models.Model):
parent = models.ForeignKey('self', blank=True, null=True, verbose_name='parent category', on_delete=models.CASCADE)
class Product(models.Model):
categories = models.ManyToManyField(Category)
name = models.CharField(max_length=255)
和产品创建表单:
class ProductModelForm(ModelForm):
class Meta:
model = Product
fields = ['categories', 'name', 'short_description', 'description']
widgets = {
'categories': MyWidget,
}
默认情况下,ManyToMany成为ModelMultipleChoiceField并对应于SelectMultiple Widget。
我正在创建一个继承自SelectMultiple的新小部件。
我的问题是,默认情况下,在所有小部件中,Django从记录中仅发送模型中def __str__
内定义的值。如果选择也是pk。
(None, [{'name': 'categories', 'value': 7, 'label': 'Category 2', 'selected': True, 'index': '1', 'attrs': {'selected': True}, 'type': 'select', 'template_name': 'django/forms/widgets/select_option.html'}]
我需要在Widget中还有其他信息,比如父值。
当然我可以进行另一次查询并从数据库中获取数据,但这意味着我有2个查询,一个由我完成,一个由Django查询。
有没有办法让Django将所有记录数据发送到窗口小部件而不仅仅是__str__
中定义的内容?
更改__str__
不是一个选项,因为它也可以在其他地方和管理员中使用。
答案 0 :(得分:1)
这不是一件容易的事:ModelChoiceField
(和ModelMultipleChoiceField
)会获取queryset
参数,默认情况下该参数是模型default_manager
( Category.objects.all()
)。使用choices
为窗口小部件生成ModelChoiceIterator
时,将使用查询集。这确实只返回了查询集中每个对象的对象id
和label
的2元组。
因此,为了确保只对数据库进行一次查询,您必须将ModelMultipleChoiceField
子类化为使用ModelChoiceIterator
的子类,该子类返回3元组(或更多元组) )使用您需要的参数。然后确保您还将__init__()
ChoiceWidget
方法(在您的情况下为SelectMultiple
)子类化为将元组再次拆分为2元组以分配给self.choices
和另一个要设置为窗口小部件属性的值(self.attrs
),以便您可以在模板中使用它们。
不确定这是否值得进行优化,特别是如果你使用一个好的缓存机制,如果你执行Category.objects.all()
两次,你实际上不会击中你的数据库两次。