问题:在Django中,如何使用动态字段查找过滤QuerySet?
给定一个Class:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=20)
是否有可能(如果有的话)有一个基于动态参数进行过滤的QuerySet?例如:
# Instead of:
Person.objects.filter(name__startswith='B')
# ... and:
Person.objects.filter(name__endswith='B')
# ... is there some way, given:
filter_by = '{0}__{1}'.format('name', 'startswith')
filter_value = 'B'
# ... that you can run the equivalent of this?
Person.objects.filter(filter_by=filter_value)
# ... which will throw an exception, since `filter_by` is not
# an attribute of `Person`.
回答 0
Python的参数扩展可用于解决此问题:
kwargs = {
'{0}__{1}'.format('name', 'startswith'): 'A',
'{0}__{1}'.format('name', 'endswith'): 'Z'
}
Person.objects.filter(**kwargs)
这是一个非常常见且有用的Python习惯用法。
回答 1
一个简化的例子:
在Django调查应用程序中,我想要一个显示注册用户的HTML选择列表。但是,因为我们有5000个注册用户,所以我需要一种基于查询条件(例如仅完成某个研讨会的人员)过滤该列表的方法。为了使调查元素可重复使用,我需要创建调查问题的人能够将那些条件附加到该问题上(不想将查询硬编码到应用程序中)。
我想出的解决方案并非100%用户友好(需要技术人员的帮助才能创建查询),但确实可以解决问题。创建问题时,编辑者可以在自定义字段中输入字典,例如:
{'is_staff':True,'last_name__startswith':'A',}
该字符串存储在数据库中。在视图代码中,它以形式返回self.question.custom_query
。该值是一个看起来像字典的字符串。我们使用eval()将其转换为真实的字典,然后使用** kwargs将其填充到查询集中:
kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")
回答 2
Django.db.models.Q正是您想要的Django方式。
回答 3
一个非常复杂的搜索表通常表明一个更简单的模型正在尝试挖掘出它的出路。
您究竟希望如何获得列名和操作的值?您从哪里获得'name'
an 的值'startswith'
?
filter_by = '%s__%s' % ('name', 'startswith')
“搜索”表格?您要-什么?-从名称列表中选择名称?从操作列表中选择操作?尽管开放式,但大多数人都觉得这令人困惑且难以使用。
有多少列具有此类过滤器?6吗 12吗 18吗
- 一些?复杂的选择列表没有任何意义。一些字段和一些if语句是有意义的。
- 大量?您的模型听起来不正确。听起来“字段”实际上是另一个表中的一行的键,而不是列的键。
特定的过滤器按钮。等等…这就是Django管理员的工作方式。特定的过滤器变成按钮。与上述分析相同。一些过滤器很有意义。大量的过滤器通常意味着一种违反第一范式的行为。
许多相似的字段通常意味着应该有更多的行和更少的字段。