Django,在模型中按功能过滤 Q 对象
Django, having Q object filter by function in model
在我的 Profile 模型中,我有以下功能:
它用于 return 用户的全名(如果缺少某些数据,则为替代名称)。
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' 过滤查询集(即从模板中的搜索框 return 编辑)
像这样:
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")它 return 没有结果。
我的大多数用户倾向于提交全名,因此作为解决方案,我尝试让它访问 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
我只想要一种方法让用户输入全名(名字 + space + 姓氏)并且仍然让程序 return 得到正确的结果。
有谁知道这样做的方法吗?
解决方案
感谢 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)
在我的 Profile 模型中,我有以下功能:
它用于 return 用户的全名(如果缺少某些数据,则为替代名称)。
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' 过滤查询集(即从模板中的搜索框 return 编辑) 像这样:
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")它 return 没有结果。
我的大多数用户倾向于提交全名,因此作为解决方案,我尝试让它访问 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
我只想要一种方法让用户输入全名(名字 + space + 姓氏)并且仍然让程序 return 得到正确的结果。
有谁知道这样做的方法吗?
解决方案
感谢 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)