Django:`__endswith`的匡威

时间:2014-07-13 17:08:59

标签: python django django-models

Django允许我这样做:

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

但我想这样做:

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

我知道查找__isendof并不存在。但是我想要这样的东西。我希望它与__endswith相反。它应该找到所有主席'hello'.endswith(chair.name)

Django可能吗? ORM操作比SQL操作更好。

3 个答案:

答案 0 :(得分:6)

Django ORM不是一个银弹,在编写部分SQL时没有任何问题,因为使用普通ORM进行处理很困难或不可能。这是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)
    
  • 然后,以下是shell中自定义__ce查询的工作方式:

    >>> 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)]    

答案 1 :(得分:1)

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

答案 2 :(得分:0)

可能就像你要得到的一样......即使它不是很棒

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