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

时间:2014-04-03 14:44:04

标签: django collation

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

4 个答案:

答案 0 :(得分:3)

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

注意使用params kwarg而不是db literal函数。 Params存在于完全相同的目的。

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 :(得分:3)

使用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数据库中使用了这个技巧。

答案 2 :(得分:1)

我使用黑客攻击来解决这个问题;

Django的extra方法与raw方法类似,它们都直接使用查询语句;

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

但是像这样的sql注入是可能的。我们需要转义name变量。我搜索了很多函数,它只是为db转义了一个字符串。在MySQL-python包中找到一个,但它无法转义unicode字符串。另外package在literal中有connection方法,但要使用它我们需要一个实例(可能是db特性)。

最后我使用了Django的db.connection.cursor

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

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

答案 3 :(得分: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