[英]Django making a query with custom collation
是否可以使用与数据库表不同的排序规则进行查询?
Using extra()
is a little messy.使用extra()
有点麻烦。 Something similar can now be achieved with Func() expression (since Django 1.8):现在可以使用Func()表达式实现类似的功能(自 Django 1.8 起):
username_ci = Func(
'username',
function='utf8_general_ci',
template='(%(expressions)s) COLLATE "%(function)s"')
This can be used in annotate()
:这可以在annotate()
:
User.objects.annotate(uname_ci=username_ci).filter(uname_ci='joeblow').exists()
Or in order_by()
to override default collation rules when sorting:或者在order_by()
在排序时覆盖默认的排序规则:
User.objects.order_by(username_ci)
Now, it still may seem messy, but if you look at the docs and code of Func() , you will discover that it is very easy to subclass it and make a reusable collation setter.现在,它看起来仍然很乱,但是如果您查看Func()的文档和代码,您会发现将其子类化并制作可重用的排序规则设置器非常容易。
I used this trick with Postgres database.我在 Postgres 数据库中使用了这个技巧。
Here is how you can use a specific collation instead of the default collation for a given table/column.以下是如何使用特定的排序规则而不是给定表/列的默认排序规则。 I'm assuming you always want that to be the case insensitive utf8_general_ci, but you can easily change that in the code or add it as a variable.我假设您总是希望它不区分大小写 utf8_general_ci,但是您可以轻松地在代码中更改它或将其添加为变量。
Note the use of the params kwarg instead of the db literal function.请注意使用 params kwarg 而不是 db 文字函数。 Params exists for the exact same purpose.参数存在的目的完全相同。
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!"
I solve this using bit of a hack;我用一点技巧解决了这个问题;
Django's extra
method is just like raw
method, they both using the query statetment directly; Django的extra
方法和raw
方法一样,都是直接使用查询语句;
MyModel.objects.extra(where=["name LIKE '%%" + name + "%%' COLLATE utf8_general_ci"])
But like this sql injection is possible.但是像这个 sql 注入是可能的。 We need to escape name
variable.我们需要转义name
变量。 I searched a lot for a function which just escapes a string for db.我搜索了很多只为 db 转义字符串的函数。 Found one in MySQL-python
package but it can't escape unicode strings.在MySQL-python
包中找到了一个,但它无法转义 unicode 字符串。 Also package has literal
method in connection
but to use it we need an instance (maybe it is for db characteristic).包也有literal
方法connection
但要使用它,我们需要一个实例(也许它是为了 db 特性)。
At last I used Django's db.connection.cursor
.最后我使用了 Django 的db.connection.cursor
。
from django.db import connection
cursor = connection.cursor()
name = cursor.db.connection.literal(name)[1:-1] # [1:-1] excluding quotes
With this way we also need an instance but I suppose this not require a db connection.通过这种方式,我们还需要一个实例,但我想这不需要数据库连接。 And I suppose this method db independent.而且我想这种方法与数据库无关。 If I am wrong please correct me.如果我错了,请纠正我。
This above solution works.上述解决方案有效。 In case of getting the reverse order the following snippet如果获得相反的顺序,请使用以下代码段
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.