【问题标题】:Django Q find user by username, first_name and/or last_nameDjango Q 通过用户名、名字和/或姓氏查找用户
【发布时间】:2015-09-08 10:41:21
【问题描述】:

我想根据数据库中的usernamefirst_namelast_name 字段查找用户。

到目前为止我所做的是:

def _build_q_for_field(fieldname, wordlist):
    def _param(x):
        return {fieldname + '__icontains': x}
    return reduce(operator.or_, (Q(**_param(w)) for w in wordlist))

query_string = "Fabian M"
query_words = query_string.strip().split(' ')  # ['Fabian', 'M']

qs = User.objects.all()
qs = qs.filter(
    _build_q_for_field('username', query_words) |
    _build_q_for_field('first_name', query_words) |
    _build_q_for_field('last_name', query_words)
)

假设我们有以下非常简单的用户集:

  • 用户 1:first_name = 'Fabian'last_name = 'Mueller'username = 'fmueller'
  • 用户 2:first_name = 'Fabian'last_name = 'Schulze'username = 'fschulze'

上面的代码将返回两个对象,因为所有条件都通过 OR 连接,并且两个用户都拥有first_name = 'Fabian'。但我希望结果集中只有用户 Fabian Mueller,因为单词列表中的第二个单词 (M) 不包含在第二个结果中。

你有一个聪明的主意如何存档吗?在过滤方法中使用 AND 而不是 OR 组合 Q 在上面的示例中确实有效,但是如果单词列表仅包含一个单词并且会立即排除用户名不匹配的结果,例如在上面的例子。

你有一个聪明的解决方案如何处理这个问题吗?提前致谢!

【问题讨论】:

    标签: python django logic


    【解决方案1】:

    如果在查询中引入一个额外的字段full_name,问题就可以解决。似乎有必要这样做,因为否则必须考虑查询中的所有字段和单词组合。可能的组合迅速爆发。

    不幸的是,Django django.db.models.functions.Concat 和 queryset.annotate() 来抽象问题。

    query_db_fields = ['first_name', 'last_name', 'username']
    
    if DJANGO_VERSION >= '1.8.0':
        from django.db.models.functions import Concat
    
        qs = qs\
             .annotate(full_name=Concat(*query_db_fields))\
             .filter(reduce(operator.and_, [Q(full_name__icontains=w) for w in query_words]))
    else:
         # (DEPRECATED) Remove this part when support for Django < 1.8 is being dropped
        for w in query_words:
            qs = qs.extra(
                 where=['lower(concat({fields:})) LIKE lower(%s)'.format(fields=','.join(query_db_fields))],
                        params=['%{}%'.format(w)]
            )
    

    【讨论】:

      猜你喜欢
      • 2010-11-25
      • 2019-01-06
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 2021-09-23
      • 2021-01-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多