Django 使用自定义排序规则进行查询

问题描述 投票:0回答:5

是否可以使用与数据库表不同的排序规则进行查询?

django collation
5个回答
13
投票

使用

extra()
有点混乱。现在可以使用 Func() 表达式实现类似的功能(自 Django 1.8 起):

username_ci = Func(
    'username',
    function='utf8_general_ci',
    template='(%(expressions)s) COLLATE "%(function)s"')

这可以用在

annotate()
:

User.objects.annotate(uname_ci=username_ci).filter(uname_ci='joeblow').exists()

或者在

order_by()
中覆盖排序时的默认排序规则:

User.objects.order_by(username_ci)

现在,它可能看起来仍然很混乱,但是如果您查看 Func() 的文档和代码,您会发现很容易对其进行子类化并创建可重用的排序规则设置器。

我在 Postgres 数据库中使用了这个技巧。


3
投票

以下是如何对给定的表/列使用特定排序规则而不是默认排序规则。我假设您总是希望不区分大小写 utf8_general_ci,但您可以轻松地在代码中更改它或将其添加为变量。

注意使用 params kwarg 而不是 db 文字函数。参数的存在是出于完全相同的目的。

def iexact(**kw):
    fields = [['%s=%%s collate utf8_general_ci'%field,value] for (field,value) in kw.items()]
    return dict(where=[f[0] for f in fields], params=[f[1] for f in fields])

if User.objects.extra(**iexact(username='joeblow')).exists():
    status = "Found a user with this username!"

1
投票

我用一点技巧解决了这个问题;

Django的

extra
方法和
raw
方法一样,都是直接使用查询语句;

MyModel.objects.extra(where=["name LIKE '%%" + name + "%%' COLLATE utf8_general_ci"])

但是像这样sql注入是可能的。我们需要转义

name
变量。我搜索了很多只转义 db 字符串的函数。在
MySQL-python
包中找到了一个,但它无法转义 unicode 字符串。包中还有
literal
方法
connection
但要使用它,我们需要一个实例(也许它是为了数据库特性)。

最后我用了Django的

db.connection.cursor

from django.db import connection
cursor = connection.cursor()
name = cursor.db.connection.literal(name)[1:-1]  # [1:-1] excluding quotes

通过这种方式,我们还需要一个实例,但我想这不需要数据库连接。我想这个方法与数据库无关。如果我错了请指正。


1
投票

上述解决方案有效。如果得到相反的顺序,请使用以下代码片段

sort_value = sort.strip()
if sort_value in ['name', '-name']:
    sort = Func('name', function='C', template='(%(expressions)s) COLLATE "%(function)s"')
if sort_value in ['-name']:
    f_res = queryset.order_by(sort).reverse()
else:
    f_res = queryset.order_by(sort)
return f_res

0
投票

我来这里时遇到了几乎同样的问题。文档说开发人员非常希望弃用 extra()。我最终得到了这个:

from django.db import models
queryset.filter(name__icontains=models.functions.Collate(models.Value(search_term), 'utf8mb4_0900_ai_ci'))
© www.soinside.com 2019 - 2024. All rights reserved.