【问题标题】:Django: Converse of `__endswith`Django:`__endswith` 的逆向
【发布时间】:2014-07-17 05:33:00
【问题描述】:

Django 允许我这样做:

chair = Chair.objects.filter(name__endswith='hello')

但我想这样做:

chair = Chair.objects.filter(name__isendof='hello')

我知道查找 __isendof 不存在。但我想要这样的东西。我希望它是 __endswith 的反面。它应该找到所有的椅子,如'hello'.endswith(chair.name)

在 Django 中可能吗? ORM 操作优于 SQL 操作。

【问题讨论】:

  • 你能举一个匹配的例子吗?
  • 这是一个奇怪的查询,您确定没有其他方法可以解决您的问题吗?
  • @Anentropic 我是个怪人。

标签: python django django-models


【解决方案1】:

Django ORM 不是灵丹妙药,如果使用普通 ORM 处理困难或不可能,编写部分 SQL 并没有错。这是extra() 的一个非常好的用例:

Entry.objects.extra(where=['"hello" LIKE CONCAT("%%", name)'])

请注意,由于我们在这里编写的是纯 SQL - 无论如何它都是特定于数据库后端的。这个特别是 mysql 特定的并且基于这个主题:MySQL: What is a reverse version of LIKE?。应该也适用于 PostgreSQL(尚未测试)。

请注意,您可以将查询调整为可重用的custom Lookup(在 Django 1.7 中引入):

  • 假设你有以下模型

    class MyModel(models.Model):
        name = models.CharField(max_length=100)
    
        def __unicode__(self):
            return self.name
    
  • 定义Lookup 类并实现as_sql() 方法:

    class ConverseEndswith(models.Lookup):
        lookup_name = 'ce'
    
        def as_sql(self, qn, connection):
            lhs, lhs_params = self.process_lhs(qn, connection)
            rhs, rhs_params = self.process_rhs(qn, connection)
            params = lhs_params + rhs_params
            return '%s LIKE CONCAT("%%%%", %s)' % (rhs, lhs), params
    
    models.Field.register_lookup(ConverseEndswith)
    
  • 那么,下面是我们自定义的__ce 查找在shell 中的工作方式:

    >>> import django
    >>> django.setup()
    >>> from myapp.models import MyModel
    >>> for name in ['hello', 'ello', 'llo', 'test1', 'test2']:
    ...     MyModel.objects.create(name=name)
    
    >>> MyModel.objects.filter(name__ce='hello')
    [<MyModel: hello>, <MyModel: ello>, <MyModel: llo>]
    >>> MyModel.objects.filter(name__ce='hello').query.__str__()
    u'SELECT `myapp_mymodel`.`id`, `myapp_mymodel`.`name` FROM `myapp_mymodel` WHERE hello LIKE CONCAT("%", `myapp_mymodel`.`name`)'
    

另一种选择是在 Python 中进行检查。由于LIKE 查询将全面扫描Entry 表中的所有记录,因此您可以使用Python 的endswith() 将它们全部获取并一一检查:

[entry for entry in Entry.objects.all() if 'hello'.endswith(entry.name)]    

【讨论】:

    【解决方案2】:

    如果你有可能使用 Django 1.7,你可以使用custom lookups。否则我认为您必须使用.extra.raw

    【讨论】:

    • 这是一个选项,但由于我不懂SQL,所以我不知道怎么写。
    【解决方案3】:

    可能会像你将要得到的一样接近......即使它不太棒

    target_string = "hello"
    chair = Chair.objects.filter(name__in=[target_string[-i:] for i in range(len(target_string))])
    

    【讨论】:

      猜你喜欢
      • 2013-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-26
      • 1970-01-01
      • 2021-08-04
      • 1970-01-01
      • 2015-05-03
      相关资源
      最近更新 更多