带替换功能的 Django 过滤器

m5s*_*pal 2 django postgresql filtering

假设我有以下模型,其中有一个方法variants():

class Example(models.Model):
    text = models.CharField(max_length=255)

    def variants(self):
        return Example.objects.filter(text=remove('xy', self.text))
Run Code Online (Sandbox Code Playgroud)

这个想法是在从文本中删除某些字符后获取文本相同的所有对象。例如,如果 self.text 是“axxyy”,则它应该与具有文本“a”的对象匹配。函数remove()不接触数据库,它返回一个删除了给定字符的新字符串。这很好用。

但是,我需要在比较的两侧执行相同的操作,以便变量()的行为如下:

    def variants(self):
        return Example.objects.filter(remove('xy', text)=remove('xy', self.text))
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果 self.txt 是 'axxyy' 它应该与 'a'、'ax、'axx'、'xayy' 等匹配,但不应该与 'aa' 匹配,因为 'a' ! = 删除后的“aa”。再说一次,我不想从数据库中删除“xy”,只是为了进行比较。

我可以用 Python 来做到这一点,但我想知道是否有办法在数据库级别上做到这一点?我一直在阅读有关 Func() 表达式的文档,例如 Replace,但尚未找到解决方案。

Tim*_*org 10

使用 django 的 Replace 函数进行注释,然后过滤该注释。

from django.db.models.functions import Replace
from django.db.models import Value
...

    def variants(self):
        return Example.objects.annotate(
            removed_x=Replace('text', Value('x'), Value('')),
            removed_xy=Replace('removed_x', Value('y'), Value('')),
        ).filter(
            removed_xy=self.text.replace('x' , '').replace('y', '')
        )
Run Code Online (Sandbox Code Playgroud)

请注意,替换参数Value('')是可选的,因为这实际上是Replace()默认值,但在示例中更明确。

随着字符数量的增长,这不能很好地扩展,但是如果您的数据库支持(Postgres),则使用正则表达式可能会有更好的解决方案