sql - 如何在没有 RawSQL 的情况下在 Django 中创建和访问正则表达式捕获组?

标签 sql regex django natural-sort

如何在不使用 RawSQL 的情况下使用 Regex 捕获组注释 Django 查询集,以便以后可以使用该值进行过滤和排序?

例如,在 PostgreSQL 中,我可以进行以下查询:

CREATE TABLE foo (id varchar(100));

INSERT INTO foo (id) VALUES ('disk1'), ('disk10'), ('disk2');

SELECT
    "foo"."id",
    CAST((regexp_matches("foo"."id", '^(.*\D)([0-9]*)$'))[2] AS integer) as grp2
FROM "foo"
ORDER BY "grp2"

dbfiddle

最佳答案

您可以使用自定义 Func创建类以使其工作,但我想以更好的方式实现,就像一个普通函数一样,可以使用其他函数或注释等进行进一步处理。就像 Django ORM 生态系统中的“块”。

我想从类的“测试版”开始,它看起来像这样:

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

class RegexpMatches(Func):
    function = 'REGEXP_MATCHES'

    def __init__(self, source, regexp, flags=None, group=None, output_field=None, **extra):
        template = '%(function)s(%(expressions)s)'

        if group:
            if not hasattr(regexp, 'resolve_expression'):
                regexp = Value(regexp)

            template = '({})[{}]'.format(template, str(group))

        expressions = (source, regexp)
        if flags:
            if not hasattr(flags, 'resolve_expression'):
                flags = Value(flags)

            expressions += (flags,)

        self.template = template

        super().__init__(*expressions, output_field=output_field, **extra)

以及一个完整的管理界面示例:
from django.contrib.admin import ModelAdmin, register
from django.db.models import IntegerField
from django.db.models.functions import Cast
from django.db.models.expressions import Func, Value

from .models import Foo


class RegexpMatches(Func):
    function = 'REGEXP_MATCHES'

    def __init__(self, source, regexp, flags=None, group=None, output_field=None, **extra):
        template = '%(function)s(%(expressions)s)'

        if group:
            if not hasattr(regexp, 'resolve_expression'):
                regexp = Value(regexp)

            template = '({})[{}]'.format(template, str(group))

        expressions = (source, regexp)
        if flags:
            if not hasattr(flags, 'resolve_expression'):
                flags = Value(flags)

            expressions += (flags,)

        self.template = template

        super().__init__(*expressions, output_field=output_field, **extra)


@register(Foo)
class Foo(ModelAdmin):
    list_display = ['id', 'required_field', 'required_field_string']

    def get_queryset(self, request):
        qs = super().get_queryset(request)

        return qs.annotate(
            required_field=Cast(RegexpMatches('id', r'^(.*\D)([0-9]*)$', group=2), output_field=IntegerField()),
            required_field_string=RegexpMatches('id', r'^(.*\D)([0-9]*)$', group=2)
        )

    def required_field(self, obj):
        return obj.required_field

    def required_field_string(self, obj):
        return obj.required_field_string

正如你在我看到的那样,我添加了 2 个注释,一个像数字一样输出,另一个像普通字符串(字符),当然,我们在管理界面中看不到它,但它在 SQL 中被执行:
SELECT "test_foo"."id" AS Col1,
               ((REGEXP_MATCHES("test_foo"."id", '^(.*\D)([0-9]*)$'))[2])::integer AS "required_field", (REGEXP_MATCHES("test_foo"."id", '^(.*\D)([0-9]*)$'))[2] AS "required_field_string"
          FROM "test_foo"

还有一个截图给你一个例子:)

REGEXP_MATCHES admin interface example with configurable group & flags & everything

Github gist with a better source code formatting https://gist.github.com/phpdude/50675114aaed953b820e5559f8d22166

关于sql - 如何在没有 RawSQL 的情况下在 Django 中创建和访问正则表达式捕获组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59198776/

相关文章:

sql - 如何在SQL Server 2008中使用三元运算符?

sql - Postgres 不会使用正确的索引

ios - NSString 正则表达式字符串匹配/搜索

ruby - 正则表达式匹配除反斜杠以外的任何字符

c# - 从公式字符串中解析出 Excel 函数

php - 检查连接表中是否不存在 id

mysql - 使用 LIKE 搜索所有列

django - DRF YASG 定制

python - 避免缩略图名称与 sorl-thumbnail 发生冲突

sql - 如何打印 django .save() 方法执行的查询?