Django中,如何通过模型中的函数对Q对象进行过滤?

5

在我的个人资料(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

现在我的问题是:我有一个视图,在这个视图中,我根据变量 '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

有趣的是,当我查看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')

Q(user__first_name__icontains=q)这行代码后面缺少一个OR运算符。 - alfonso.kim
哎呀,看起来当我复制/编辑帖子的代码时它丢失了。 - Jasper
1个回答

5

尝试使用数据库函数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)

非常感谢!我能够使用这段代码让我的程序正常工作了。我会相应地更新我的问题。 - Jasper

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接