如何在不使用 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"
还有一个截图给你一个例子:)
Github gist with a better source code formatting https://gist.github.com/phpdude/50675114aaed953b820e5559f8d22166
关于sql - 如何在没有 RawSQL 的情况下在 Django 中创建和访问正则表达式捕获组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59198776/