【问题标题】:Django making a query with custom collationDjango 使用自定义排序规则进行查询
【发布时间】:2014-05-15 11:43:01
【问题描述】:

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

【问题讨论】:

  • 您想在现有数据库上使用不同排序规则的 django 模型,还是想在 django 模型框架之外进行查询?
  • 嗯,使用不同的排序规则似乎工作正常,但将来我可能需要使用排序规则数据库进行查询。如果可能的话,我更喜欢仅对该查询使用不同的排序规则。 “超越 django 的模型框架”是指原始 sql 查询吗?
  • 是的,如果你想使用不属于 django 数据库的数据库。
  • 我有一个名为name 的专栏是独一无二的。在我的语言字符öo 不同,因此它更改为与utf8_general_ci 不同的排序规则。但知道我想用öo 进行搜索查询。
  • 为什么?我想使用排序规则utf8_general_ci 进行查询,哪个数据库列排序规则不同。你的意思是我需要以不同于自定义排序规则查询的方式来解决这个问题?

标签: django collation


【解决方案1】:

使用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】:

    以下是如何使用特定排序规则而不是给定表/列的默认排序规则。我假设您总是希望它是不区分大小写的 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!"
    

    【讨论】:

    • 哦,当您专注于某件事时,您不会想到其他选择。我阅读了 django where 使用文档近 3 次,但我无法意识到这一点,这很尴尬 :) 这就是答案。谢谢你:)
    【解决方案3】:

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

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

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

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

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

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

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

    【讨论】:

    • 仅供参考:以这种方式使用带有参数的.extra()不安全!有关该主题的更多信息:blog.r2c.dev/2020/…
    【解决方案4】:

    上述解决方案有效。如果得到相反的顺序,则以下 sn-p

    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
    

    【讨论】:

      猜你喜欢
      • 2013-09-26
      • 2011-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-10
      • 1970-01-01
      • 1970-01-01
      • 2019-05-19
      相关资源
      最近更新 更多