Django过滤器,更换
假设我有以下模型,其中有一个方法variants(): 其思想是在从文本中删除某些字符后,获取文本相同的所有对象。例如,如果self.text为“axxyy”,则它应与包含文本“a”的对象匹配。函数remove()不接触数据库,它返回一个已删除给定字符的新字符串。这个很好用 但是,我需要在比较的两侧执行相同的操作,以便variants()的行为如下所示:Django过滤器,更换,django,postgresql,filtering,Django,Postgresql,Filtering,假设我有以下模型,其中有一个方法variants(): 其思想是在从文本中删除某些字符后,获取文本相同的所有对象。例如,如果self.text为“axxyy”,则它应与包含文本“a”的对象匹配。函数remove()不接触数据库,它返回一个已删除给定字符的新字符串。这个很好用 但是,我需要在比较的两侧执行相同的操作,以便variants()的行为如下所示: def variants(self): return Example.objects.filter(remove('x
def variants(self):
return Example.objects.filter(remove('xy', text)=remove('xy', self.text))
在这种情况下,如果self.txt是'axxyy',它应该与'a','ax','axx','xayy'等匹配,但不应该与'aa'匹配,例如,因为'a'!='aa'在拆除后。再一次,我不想从数据库中删除'xy',只是为了比较
我可以用Python实现这一点,但我想知道是否有一种方法可以在数据库级别实现这一点?我一直在阅读有关Func()表达式的文档,例如Replace,但还没有找到解决方案。使用django的Replace函数进行注释,然后对该注释进行筛选
从django.db.models.functions导入替换
从django.db.models导入值
...
def变体(自身):
返回Example.objects.annotate(
已删除\u x=替换('text',Value('x'),Value(''),
移除的_xy=替换('removed_x',Value('y'),Value('')),
).过滤器(
已删除_xy=self.text.replace('x','').replace('y','')
)
请注意,替换参数Value(“”)
是可选的,因为这实际上是Replace()
的默认值,但在示例中更显式
随着字符数的增加,这种方法不能很好地扩展,但是如果您的DB支持使用django的Replace函数进行注释(Postgres),那么使用regex可能会有更好的解决方案,然后对该注释进行过滤
从django.db.models.functions导入替换
从django.db.models导入值
...
def变体(自身):
返回Example.objects.annotate(
已删除\u x=替换('text',Value('x'),Value(''),
移除的_xy=替换('removed_x',Value('y'),Value('')),
).过滤器(
已删除_xy=self.text.replace('x','').replace('y','')
)
请注意,替换参数Value(“”)
是可选的,因为这实际上是Replace()
的默认值,但在示例中更显式
随着字符数的增加,这种方法不能很好地扩展,但是如果您的DB支持正则表达式,那么使用正则表达式可能会有更好的解决方案(Postgres)我在回答我自己的问题,因为我能够在Tim Nyborg的答案的帮助下实现这一点。我不确定这是否是实现这一点的最漂亮、最有效的方法,但它似乎可以很快地处理我正在处理的数据量,并且可以很好地扩展以适应不断增长的替换模式。此解决方案仅适用于Postgres,因为它使用“regexp_replace”进行替换 以下是示例实现:
def variants(self):
patterns = [
('[xyz️w]', ''),
('[\u00A0]', ' '),
# etc.
]
# Replace characters in self.text
text_i = self.text
for old, new in patterns:
text_i = re.sub(old, new, text_i)
# Replace the same characters in all other objects
queryset = Example.objects.all()
for i, value in enumerate(patterns):
old, new = value
queryset = queryset.annotate(
**{f'text_{i}': Func(F(f'text_{i - 1}' if i > 0 else 'text'),
Value(old), Value(new), Value('g'),
function='regexp_replace')})
else:
# Filter all where replaced texts are the same
queryset = queryset.filter(**{f'text_{i}': text_i}).exclude(pk=self.pk)
return queryset
Regex本身解决了大多数问题,因为可以一次替换多个字符,但我的模式相当复杂,所以我将它们拆分为列表,并用动态构建的字段名进行注释
话虽如此,如果我真的继续使用这个解决方案,或者更确切地说,在模型中添加一个字段来存储每个对象的“text_I”(替换已完成)值,那么我还不是100%,然后就这样做:
def variants(self):
return Example.objects.filter(text_i=self.text_i).exclude(pk=self.pk)
我只需要考虑“Tr.Tythi”是否足够稳定,这样我就不必在最初的创作后不断地更新它们。 < P>我回答了我自己的问题,因为我能够在Tim Nyborg的回答的帮助下完成这项工作。我不确定这是否是实现这一点的最漂亮、最有效的方法,但它似乎可以很快地处理我正在处理的数据量,并且可以很好地扩展以适应不断增长的替换模式。此解决方案仅适用于Postgres,因为它使用“regexp_replace”进行替换 以下是示例实现:
def variants(self):
patterns = [
('[xyz️w]', ''),
('[\u00A0]', ' '),
# etc.
]
# Replace characters in self.text
text_i = self.text
for old, new in patterns:
text_i = re.sub(old, new, text_i)
# Replace the same characters in all other objects
queryset = Example.objects.all()
for i, value in enumerate(patterns):
old, new = value
queryset = queryset.annotate(
**{f'text_{i}': Func(F(f'text_{i - 1}' if i > 0 else 'text'),
Value(old), Value(new), Value('g'),
function='regexp_replace')})
else:
# Filter all where replaced texts are the same
queryset = queryset.filter(**{f'text_{i}': text_i}).exclude(pk=self.pk)
return queryset
Regex本身解决了大多数问题,因为可以一次替换多个字符,但我的模式相当复杂,所以我将它们拆分为列表,并用动态构建的字段名进行注释
话虽如此,如果我真的继续使用这个解决方案,或者更确切地说,在模型中添加一个字段来存储每个对象的“text_I”(替换已完成)值,那么我还不是100%,然后就这样做:
def variants(self):
return Example.objects.filter(text_i=self.text_i).exclude(pk=self.pk)
我只需考虑“TrimeI i”是否足够稳定,以便在最初创建之后不必不断地更新它们。
确实如此,如果只替换一个或两个字符串,这是一个很好的解决方案。我必须删除至少五个字符,这样就有点复杂了。我一直在寻找类似Replace('text',Value('xyzw'),Value('')这样的东西,以使另一面更简单。无论如何,尽管这个精确的解决方案对我来说不是最优的,但对于其他类似的用例来说,它可能是一个很好的解决方案,您的回答也给了我一个如何继续的想法。我用的是Postgres,所以正则表达式可能是最好的选择。我会接受这个答案,谢谢你的帮助!这确实有效,如果您只有一个或两个字符串需要替换,那么这是一个很好的解决方案。我必须删除至少五个字符,这样就有点复杂了。我一直在寻找类似Replace('text',Value('xyzw'),Value('')这样的东西,以使另一面更简单。无论如何,尽管这个精确的解决方案对我来说不是最优的,但对于其他类似的用例来说,它可能是一个很好的解决方案,您的回答也给了我一个如何继续的想法。我用的是Postgres,所以正则表达式可能是最好的选择。我会接受这个答案,谢谢你的帮助!