将所有记录数据获取到Widget而不在数据库中创建新查询

时间:2017-11-22 08:55:11

标签: django django-models django-forms django-widget

我有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__不是一个选项,因为它也可以在其他地方和管理员中使用。

1 个答案:

答案 0 :(得分:1)

这不是一件容易的事:ModelChoiceField(和ModelMultipleChoiceField)会获取queryset参数,默认情况下该参数是模型default_managerCategory.objects.all())。使用choices为窗口小部件生成ModelChoiceIterator时,将使用查询集。这确实只返回了查询集中每个对象的对象idlabel的2元组。

因此,为了确保只对数据库进行一次查询,您必须将ModelMultipleChoiceField子类化为使用ModelChoiceIterator的子类,该子类返回3元组(或更多元组) )使用您需要的参数。然后确保您还将__init__() ChoiceWidget方法(在您的情况下为SelectMultiple)子类化为将元组再次拆分为2元组以分配给self.choices和另一个要设置为窗口小部件属性的值(self.attrs),以便您可以在模板中使用它们。

不确定这是否值得进行优化,特别是如果你使用一个好的缓存机制,如果你执行Category.objects.all()两次,你实际上不会击中你的数据库两次。