Django: Converse `__endswith`

Django allows me to do this:

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

But I want to do this:

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

I know that __isendof search __isendof not exist. But I want something like this. I want this to be the opposite of __endswith . He must find all the chairs to 'hello'.endswith(chair.name) .

Maybe in Django? ORM operations are preferred over SQL.

+6
source share
3 answers

Django ORM is not a silver bullet, there is nothing wrong with writing parts of SQL if processing with a simple ORM is difficult or impossible. This is a really good use case for extra() :

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

Please note that since we are writing plain SQL here, this will be relevant to the database anyway. This particular mysql type is specific and based on this topic: MySQL: what is the reverse version of LIKE? . It should work for PostgreSQL (not tested).

Please note that you can adapt the request to reusable custom Lookup (introduced in Django 1.7):

  • imagine you have the following model

     class MyModel(models.Model): name = models.CharField(max_length=100) def __unicode__(self): return self.name 
  • Define the Lookup class with the implemented as_sql() method:

     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) 
  • then this is how our custom __ce search works in the 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`)' 

Another option is to do a check in Python. Since the LIKE query will do a full scan of all the records inside the Entry table, you can get them all and check them one by one using Python endswith() :

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

If you have the opportunity to use Django 1.7, you can use custom search queries . Otherwise, I think you need to use .extra or .raw .

+1
source

perhaps something like as close as you are going to get ... although its less than amazing

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

Source: https://habr.com/ru/post/972142/


All Articles