【问题标题】:How do i disregard a django filter field if the field is empty?如果字段为空,我如何忽略 django 过滤器字段?
【发布时间】:2020-01-29 10:46:04
【问题描述】:

所以,我开始为我的 django 应用程序编写一个过滤系统。是这样的

class Person(models.Model):
     first_name = models.CharField(max_length = 50)
     middle_name = models.CharField(max_length = 50)
     last_name = models.CharField(max_length = 50)

如果其他字段为空,我想过滤哪个 Person 的字段包含 x 值,就像这个算法一样

results = Person.objects.filter(first_name__contains = "a")

但如果其他字段不为空,我想像这样过滤它

results = Person.objects.filter(first_name__contains = "a", middle_name__contains = "a", last_name__contains = "a")

取决于哪些字段没有空值。

我的第一次尝试是这样的:

if first_name != "":
     results = Person.objects.filter(first_name__contains = first_name)
if middle_name != "":
     results = results.filter(middle_name__contains = middle_name)
if last_name != "":
     results = results.filter(last_name__contains = last_name)

我的问题是它按顺序过滤它,所以如果我只过滤middle_name 或只过滤last_name,它会返回一个错误,因为results 尚未定义,有人可以帮我解决这个问题吗?

有这样的算法吗? results = Person.objects.filter(first_name__contains = first_name if first_name != "" else JUST REMOVE THIS FILTER)? 因为如果它过滤 "" 它将返回您的所有数据。提前谢谢你

【问题讨论】:

    标签: django django-models


    【解决方案1】:

    您可以分阶段构建查询集

    qs = Person.objects.all()
    if first_name != "":
       qs = qs.filter( first_name__contains=first_name )
    if middle_name != "":
       qs = qs.filter( middle_name__contains=middle_name )
    if last_name != "":
       qs = qs.filter( last_name__contains=last_name )
    

    您可以对 Q objects 执行相同的操作以进行 OR 类型匹配(这有点繁琐)

    qs = Person.objects.all()
    q = None
    for op, name in (( "first_name__contains", first_name),
                     ( "middle_name__contains", middle_name),
                     ( "last_name__contains",  last_name)) :
    
        if name != "":
            if q:
                q = q | Q( **{ op: name} )
            else
                q =     Q( **{ op: name} )
    
    if q:
        qs = qs.filter(q)
    

    【讨论】:

    • 谢谢。自从您告诉我以来,我没有意识到这一点,因为我使用 Person.objects.none() 开始了我的函数,因为我将它用作 ajax 来让它知道如果所有字段都为空则返回 none。现在,我的代码是这样的。 results = Person.objects.none() if first_name != "" and middle_name != "" and last_name != "": ` results = Person.objects.all()` ` if first_name != "":` ` results = results.filter(first_name__contains = first_name)` ` ...`
    • 我的意思是if first_name != "" or middle_name != "" or last_name != ""
    • 一个简单的错误。我总是更喜欢if any([ first_name != "", ..., last_name != ""]) :if all([...]) 在适当的情况下。依赖空字符串作为虚假值也是 Pythonic:if any([ first_name, middle_name, last_name ]) :
    • 我要添加,注意空格是否真实并使用.strip(),如果您隐约记得“Someone de la Something”,那么对姓氏中的空格进行过滤是非常明智的。
    【解决方案2】:

    简单来说,当查询提供的特定字符串时,您希望在first_namelast_namemiddle_name 之间执行ORing。

    我强烈推荐你在 Django 中使用 Q Object Lookups

    您的代码将更简单,如下所示:

    text = 'a'
    results = Person.objects.filter(Q(first_name__contains=text) | Q(middle_name__contains=text) | Q(last_name__contains=text))
    

    【讨论】:

    • 作者提到这一点:if other fields are empty, like this algorithm,在您的示例中,它只选择带有OR 运算符的记录。
    • Radwan 是对的,但仍然感谢您的评论,我目前正在寻找 Q Object Lookups。非常感谢。
    猜你喜欢
    • 2021-09-10
    • 2019-12-16
    • 2021-06-19
    • 2019-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多