如何连接表django模型的两列

Bug*_*ter 8 python mysql django

我在我的项目中实现搜索我想要的是在where子句中连接到列以从表中获取结果.

这是我在做的事情:

from django.db.models import Q

if 'search[value]' in request.POST and len(request.POST['search[value]']) >= 3:
    search_value = request.POST['search[value]'].strip()

    q.extend([
        Q(id__icontains=request.POST['search[value]']) |
        (Q(created_by__first_name=request.POST['search[value]']) & Q(created_for=None)) |
        Q(created_for__first_name=request.POST['search[value]']) |
        (Q(created_by__last_name=request.POST['search[value]']) & Q(created_for=None)) |
        Q(created_for__last_name=request.POST['search[value]']) |
        (Q(created_by__email__icontains=search_value) & Q(created_for=None)) |
        Q(created_for__email__icontains=search_value) |
        Q(ticket_category=request.POST['search[value]']) |
        Q(status__icontains=request.POST['search[value]']) |
        Q(issue_type__icontains=request.POST['search[value]']) |
        Q(title__icontains=request.POST['search[value]']) |
        Q(assigned_to__first_name__icontains=request.POST['search[value]']) |

    ])
Run Code Online (Sandbox Code Playgroud)

现在我想添加另一个OR条件,如:

CONCAT(' ', created_by__first_name, created_by__last_name) like '%'search_value'%"

但是当我将这个条件添加到查询集时,它变为AND

where = ["CONCAT_WS(' ', profiles_userprofile.first_name, profiles_userprofile.last_name) like '"+request.POST['search[value]']+"' "]
            tickets = Ticket.objects.get_active(u, page_type).filter(*q).extra(where=where).exclude(*exq).order_by(*order_dash)[cur:cur_length]
Run Code Online (Sandbox Code Playgroud)

如何将其转换为OR条件?

hyn*_*cer 6

高级过滤器可以通过Q()对象和Func(),Value()和F()等 Query表达式来解决 .唯一使用的技巧是 自定义查找 "rhs_only",它使用查找的右侧并忽略左侧,因为更容易直接在右侧使用所有连接字段.一个令人难忘的功能concat_like封装了所有在查询中易于使用的功能.

from django.db.models import F, Func, Lookup, Q, Value
from django.db.models.fields import Field

def concat_like(columns, pattern):
    """Lookup filter: CONCAT_WS(' ', column_0, column_1...) LIKE pattern"""
    lhs = '%s__rhs_only' % columns[0]
    expr = Func(*(F(x) for x in columns), template="CONCAT_WS(' ', %(expressions)s)")
    return Q(**{lhs: Like(expr, Value(pattern))})

class Like(Func):
    def as_sql(self, compiler, connection):
        arg_sql, arg_params = zip(*[compiler.compile(x) for x in self.source_expressions])
        return ("%s LIKE '%s'" % tuple(arg_sql)), arg_params[0] + arg_params[1]

@Field.register_lookup
class RhsOnly(Lookup):
    """Skip the LHS and evaluate the boolean RHS only"""
    lookup_name = 'rhs_only'

    def as_sql(self, compiler, connection):
        return self.process_rhs(compiler, connection)
Run Code Online (Sandbox Code Playgroud)

此代码支持所有布尔表达式和相关对象.所有参数都被正确转义.

用法示例:

>>> qs = MyModel.objects.filter(Q(id=1) | concat_like(('first_name', 'surname'), 'searched'))
>>> str(qs.query)   # sql output simplified here
"SELECT .. WHERE id=1 OR (CONCAT_WS(' ', first_name, surname) LIKE 'searched')"  
Run Code Online (Sandbox Code Playgroud)


Gre*_*ian 5

相关文档:

您可以从过滤器方法内部引用带注释的字段。因此,您可以过滤两个连接的字段并将其添加为另一个 OR 条件,如下所示:

from django.db.models import F, Func, Value

# Because we added user_full_name as an annotation below,
# we can refer to it in the filters
q.extend([
    Q(id__icontains=request.POST['search[value]']) |
    (Q(created_by__first_name=request.POST['search[value]']) & Q(created_for=None)) |
    Q(created_for__first_name=request.POST['search[value]']) |
    (Q(created_by__last_name=request.POST['search[value]']) & Q(created_for=None)) |
    Q(created_for__last_name=request.POST['search[value]']) |
    (Q(created_by__email__icontains=search_value) & Q(created_for=None)) |
    Q(created_for__email__icontains=search_value) |
    Q(ticket_category=request.POST['search[value]']) |
    Q(status__icontains=request.POST['search[value]']) |
    Q(issue_type__icontains=request.POST['search[value]']) |
    Q(title__icontains=request.POST['search[value]']) |
    Q(assigned_to__first_name__icontains=request.POST['search[value]']) |
    Q(user_full_name__icontains=request.POST['search[value]'])  # <------
])


# Add the annotation to your queryset
# I'm not actually sure what the related_name or field_name for your user
# profiles are, so I'm pretending that tickets have a profile foreignkey field
# to where the first_name and last_name fields are
user_full_name_expr = Func(Value(' '), F('profile__first_name'), F('profile__last_name'), function='CONCAT_WS')

# The next two lines can be combined as long as the annotation comes first.
tickets = Ticket.objects.annotate(user_full_name=user_full_name_expr)
tickets = tickets.get_active(u, page_type).filter(*q).exclude(*exq).order_by(*order_dash)[cur:cur_length]
Run Code Online (Sandbox Code Playgroud)

为了好玩,这里有一个基于 User 模型的工作示例。

from django.contrib.auth.models import User
from django.db.models import F, Func, Value

User.objects.create(username='john', first_name='John', last_name='Jingleheimer-Schmidt')
User.objects.create(username='mike', first_name='Michael', last_name='Finnigan')

foo = User.objects.annotate(full_name=Func(Value(' '), F('first_name'), F('last_name'), function='CONCAT_WS'))
print(foo.filter(full_name__icontains='john'))

# outputs: [<User: john>]
Run Code Online (Sandbox Code Playgroud)


Eli*_*iro 3

您需要的是创建搜索全文。我建议使用(http://haystacksearch.org/

请参阅 Django 文档 ( https://docs.djangoproject.com/en/1.11/ref/contrib/postgres/search/ )