sou*_*eux 1 python django django-forms django-queryset
我在两个不同的地方使用一段代码,以便动态生成一些表单字段。在这两种情况下,dynamic_fields都是一个字典,其中的键是对象,值是对象列表(在空列表的情况下,值是False):
class ExampleForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
dynamic_fields = kwargs.pop('dynamic_fields')
super(ExampleForm, self).__init__(*args, **kwargs)
for key in dynamic_fields:
if dynamic_fields[key]:
self.fields[key.description] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple, queryset=dynamic_fields[key], required=False)
class Meta:
model = Foo
fields = ()
Run Code Online (Sandbox Code Playgroud)
在一个视图中,对于任何键,该值都是通过单个数据库查询(单个正常查询集)返回的对象列表。这种观点很好。
在另一个视图中,它需要多个查询才能获得构造给定值所需的一切。我首先实例化具有等于空白列表的值的字典,然后使用基本列表理解(dict[key] += queryset)一次将从这些多个查询中获得的查询集添加到适当的列表中。这使每个值成为一个二维列表,然后通过执行以下操作将其展平(并删除重复项):
for key in dict:
dict[key] = list(set(dict[key]))
Run Code Online (Sandbox Code Playgroud)
我尝试了几种不同的方法-将每个查询集中的查询直接附加到值/列表,使用append而不是将其保留为列表列表,+=但每次都会遇到相同的错误:'list' object has no attribute 'none'。
通过回溯查看,错误出现在表单的clean方法中。这是django.forms.models中代码的相关部分:
def clean(self, value):
if self.required and not value:
raise ValidationError(self.error_messages['required'], code='required')
elif not self.required and not value:
return self.queryset.none() # the offending line
Run Code Online (Sandbox Code Playgroud)
到目前为止,我的思考过程是:在第一个视图中,我正在通过单个查询生成用作每个键的值的列表,但是在第二个视图中,我将多个查询组合到一个列表中。该列表没有none像通常使用单个查询集那样的方法。
如何合并多个查询集,而又不会失去对该方法的访问权限?
我找到了这篇文章,但是我仍然遇到itertools.chain与建议相同的问题。我唯一能够完成的事情就是将错误改为'chain'或'set' object has no attribute 'none'。
编辑:这是有关如何生成查询集的一些其他信息。我有以下模型(仅显示相关字段):
class Profile(models.Model):
user = models.OneToOneField(User)
preferred_genres = models.ManyToManyField(Genre, blank=True)
class Genre(models.Model):
description = models.CharField(max_length=200, unique=True)
parent = models.ForeignKey("Genre", null=True, blank=True)
class Trope(models.Model):
description = models.CharField(max_length=200, unique=True)
genre_relation = models.ManyToManyField(Genre)
Run Code Online (Sandbox Code Playgroud)
在(工作状态)视图1中,我用来生成字段的字典的键等于某个流派,其值等于该键为父的流派列表。换句话说,对于每个键,queryset为Genre.objects.filter(parent=key, **kwargs)。
在非功能性视图#2中,我们需要从配置文件的preferred_genres字段开始。对于每一个preferred_genre我需要拉相关联Tropes,并将它们组合成一个查询集。现在,我正在遍历preferred_genres并执行以下操作:
for g in preferred_genres:
tropeset = g.trope_set.all()
Run Code Online (Sandbox Code Playgroud)
这使我得到了一堆包含我所需信息的单独查询集,但是我找不到一种将多个查询集组合tropesets成一个大查询集的方法(与没有该none属性的列表相对)。(顺便说一句,这也使我的数据库受到一堆查询的困扰。我也想尽我所能解决如何使用prefetch_related减少查询数量的问题,但一次只能解决一件事。)
如果我不能将这些查询集合并为一个,但是可以通过一个查询以某种方式完成这些查询,那我真是无所不能!我现在正在阅读有关使用Q对象进行复杂查询的文档。令人着迷的是-我可以概念化这将如何完成我要寻找的东西,但前提是我可以一次调用所有查询。因为我给他们打电话反复一次一个,我不知道如何使用默认的Q对象|或&在一起。
您可以使用|和&运算符组合查询集。
from functools import reduce
from operator import and_, or_
querysets = [q1, q2, q3, ...] # List of querysets you want to combine.
# Objects that are present in *at least one* of the queries
combined_or_querysets = reduce(or_, querysets[1:], querysets[0])
# Objects that are present in *all* of the queries
combined_and_querysets = reduce(and_, querysets[1:], querysets[0])
Run Code Online (Sandbox Code Playgroud)
从Django 1.11+开始,您还可以使用union和intersection方法。