【问题标题】:Django: Is there a way to filter a model and ignore a stored hyphen?Django:有没有办法过滤模型并忽略存储的连字符?
【发布时间】:2020-04-28 06:13:34
【问题描述】:

我有一个这样的模型:

class Product(models.Model):
   name = models.CharField(max_length=5)

名称示例:A-123

是否可以过滤此名称字段,以便我可以输入连字符或将其省略,并获得相同的结果?例如,查询“A-123”和“A123”将返回相同的项目。使用常规过滤器,我只有在执行“A-123”时才会得到结果。

如果不是,最好的解决方案是制作一个填充辅助“可搜索”字段的 on_save 触发器吗?

这将是我最初的想法,但我担心这会效率低下。

我考虑过的另一种方法是拉出所有对象,然后循环并删除连字符以找到匹配项,但我再次担心性能问题/效率。

【问题讨论】:

  • 你能告诉我们你的过滤查询吗?
  • 当然!当前过滤器将是 product = Product.objects.filter(name="A123") 但是这不会返回任何结果。
  • 你可以使用 __contains 或 __icontains(不区分大小写)
  • 当我运行这个过滤器时,Product.objects.get(sku__contains="A123"),我没有得到任何结果。
  • @popcorn 这可能有点冒险。如果您开始使用 LIKE,A-123 也会返回 BA-123。

标签: python django


【解决方案1】:

添加一个具有标准化名称的字段将是一个明智的解决方案,尽管我会通过在 Product 模型上覆盖 .save() 来填充它。

class Product(models.Model):
    name = models.CharField(max_length=5)
    normalized_name = models.CharField(max_length=5)

    def save(self, *args, **kwargs):
        self.normalized_name = self.normalize_name(name)
        super().save(*args, **kwargs)

    @classmethod
    def normalize_name(cls, name):
        return name.replace('-', '')  # Maybe also remove spaces?


Product.objects.filter(normalized_name=Product.normalize_name('A-123'))
Product.objects.filter(normalized_name=Product.normalize_name('A123'))

如果您在多个地方使用它,您可能需要创建一个自定义管理器以避免代码重复:

class ProductManager(models.Manager):

    def filter_by_normalized_name(name):
        normalized_name = Product.normalize_name('A-123')
        return self.get_queryset().filter(normalized_name=normalized_name)


class Product(models.Model):

    ...
    objects = ProductManager

Product.objects.filter_by_normalized_name('A123')
Product.objects.filter_by_normalized_name('A-123')

或者,如果Product.name 始终具有相同的结构,您可以规范化您的搜索词。

例如如果您知道该名称始终以连字符作为第二个字符:

if search_term[1] != '-':
    search_term = f"{search_term[0]}-{search_term[1:]}"

对于更详细的解决方案,您可能需要使用 PostgreSQL 或 ElasticSearch 进行全文搜索。

【讨论】:

  • 感谢您的回复!定制经理有什么好处?我只是问,因为这是我尚未探索的 Django 的一个方面。
  • 避免代码重复。我已经扩展了我的答案来说明它。
【解决方案2】:

我喜欢您填充规范化字段的想法,因为感觉它会提供最佳性能,因为您可以索引该字段。但是,如果这不是问题,您可以use regex in your queryset filter。要同时查询A-123A123,您可以使用^A-?123$ 之类的正则表达式。

【讨论】:

    猜你喜欢
    • 2022-01-20
    • 1970-01-01
    • 2019-08-16
    • 2020-12-28
    • 1970-01-01
    • 2022-06-16
    • 2020-05-10
    • 1970-01-01
    • 2012-12-02
    相关资源
    最近更新 更多