无需在数据库中进行新查询,即可将所有记录数据获取到 Widget
Get all records data to a Widget without making a new Query in the database
我有 2 个模型产品和类别 - 多对多关系产品类别和类别的自外键
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__
中定义的值。如果 Select 也 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__
不是一个选项,因为它也在其他地方和管理中使用。
这不是很容易:ModelChoiceField
(和 ModelMultipleChoiceField
)采用 queryset
参数,默认情况下是模型的 default_manager
(Category.objects.all()
) .当使用 ModelChoiceIterator
为小部件生成 choices
时,将使用查询集。对于查询集中的每个对象,确实只有 returns 对象的 id
和 label
的二元组。
因此,为了确保只有一个对数据库的查询,您必须继承 ModelMultipleChoiceField
以使用 ModelChoiceIterator
的子类,其中 returns 一个 3 元组(或更多) 与你需要的参数。然后确保您还子类化 ChoiceWidget
的 __init__()
方法(在您的情况下 SelectMultiple
)以将元组再次拆分为一个 2 元组以分配给 self.choices
和另一个值设置为小部件属性 (self.attrs
),以便您可以在模板中使用它们。
不确定这是否值得您进行优化,特别是如果您使用良好的缓存机制,如果您执行 Category.objects.all()
两次,您实际上不会访问数据库两次。
我有 2 个模型产品和类别 - 多对多关系产品类别和类别的自外键
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__
中定义的值。如果 Select 也 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__
不是一个选项,因为它也在其他地方和管理中使用。
这不是很容易:ModelChoiceField
(和 ModelMultipleChoiceField
)采用 queryset
参数,默认情况下是模型的 default_manager
(Category.objects.all()
) .当使用 ModelChoiceIterator
为小部件生成 choices
时,将使用查询集。对于查询集中的每个对象,确实只有 returns 对象的 id
和 label
的二元组。
因此,为了确保只有一个对数据库的查询,您必须继承 ModelMultipleChoiceField
以使用 ModelChoiceIterator
的子类,其中 returns 一个 3 元组(或更多) 与你需要的参数。然后确保您还子类化 ChoiceWidget
的 __init__()
方法(在您的情况下 SelectMultiple
)以将元组再次拆分为一个 2 元组以分配给 self.choices
和另一个值设置为小部件属性 (self.attrs
),以便您可以在模板中使用它们。
不确定这是否值得您进行优化,特别是如果您使用良好的缓存机制,如果您执行 Category.objects.all()
两次,您实际上不会访问数据库两次。