Django,在模型中按函数过滤 Q 对象

标签 django django-queryset django-q

在我的 Profile 模型中,我具有以下功能:

它用于返回用户的全名(如果某些数据丢失,则可以使用替代方法)。

    def full_name(self):
      first_name = self.user.first_name.strip()
      if first_name and self.user.last_name:
          if not self.middle_name:
              full_name = u'%s %s' % (first_name, self.user.last_name)
          else:
              full_name = u'%s %s %s' % (first_name, self.middle_name,
                                       self.user.last_name)
          return full_name.strip()
      elif first_name:
          return first_name
      return self.user.username

现在我的问题:我有一个 View ,我根据变量“q”(从模板中的搜索框返回)过滤查询集
像这样:
qs = qs.filter(tenant_demo_purchase=True).order_by('-id')
    #Search users within results
    q = self.request.GET.get('q', None)
    if q:
        qs = qs.filter(Q(user__username__icontains=q) |
                       Q(user__first_name__icontains=q) |
                       Q(user__last_name__icontains=q) |
                       Q(arrangement_period__arrangement__title__icontains=q)  | 
                       ).filter(tenant_demo_purchase=True).order_by('-id')
    else:
        pass
    return qs

如果我给它一个名字、用户名或姓氏,这个过滤器就可以正常工作。但是如果我给它一个名字+姓氏(例如:“John Doe”),它不会返回任何结果。

我的大多数用户倾向于提交全名,因此作为一种解决方案,我试图让它访问 Profile.full_name 函数。通过添加以下行
Q(user__profile__fullname__icontains=q) 

但是,这会崩溃并显示以下错误消息:
raise FieldError('Related Field got invalid lookup: {}'.format(lookups[0]))
FieldError: Related Field got invalid lookup: fullname

Interistengly,当我查看 django 错误页面时,它似乎忽略了用户名并在 'arrangement__title' 查询中失败,忽略了其余部分:
 Q(arrangement_period__arrangement__title__icontains=q)

我尝试做显而易见的事情:
Q(user__profile.fullname__icontains=q) 

但这只会引发以下错误
SyntaxError: keyword can't be an expression

我只想要一种让用户输入全名(名字 + 空格 + 姓氏)并仍然让程序返回正确结果的方法。

有谁知道这样做的方法吗?

解决方案

感谢 Ivan 他的回答,以下代码提供了所需的结果:
q = self.request.GET.get('q', None)
    if q:
        qs = qs.annotate(
            full_name=Concat(
                'user__first_name',
                Value(' '),
                'user__last_name',
                output_field=CharField()
            )
        ).filter(Q(full_name__icontains=q) |
                 Q(user__username__icontains=q) |
                 Q(user__first_name__icontains=q) |
                 Q(user__last_name__icontains=q) |
                 Q(arrangement_period__arrangement__title__icontains=q)
                 ).order_by('-id')

最佳答案

尝试使用数据库函数 concat:

from django.db.models import CharField, Value
from django.db.models.functions import Concat


qs = qs.annotate(
    full_name=Concat(
        'user__first_name',
        Value(' '),
        'user__last_name',
        output_field=CharField()
    )
).filter(full_name__icontains=q)

关于Django,在模型中按函数过滤 Q 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46688826/

相关文章:

django - 在 Django Admin 中为 list_filter 创建自定义过滤器

django - 创建实例时如何更新 ManyToManyField

Django 过滤父级,其中所有子值都符合条件

python - Django:为相关表构建动态 Q 查询

django - 在 Django 1.5 中验证自定义用户

django - 使用 chrome 扩展和 Django 进行身份验证

Django 查询集 EXCLUDE : are these equivalent?

python - Django ORM 的奇怪行为

django - 动态组合 Q() - OR 对象

python - 使用带有变量的 Q 对象