How to get all the people starting with the list of letters?

In the database has a list of people. It is necessary if people.name begins with the letter listed then pick it up from the database. As such a filter to do that? Ie is not just a filter, startswith, and so it is with any of the letters in the list could the name begin. For example to pick up all people whose name begins with D. In for And have a request to make necessary. You can't take the entire list and means Python to filter out the desired.

Found here such method (though not yet tested)
Model.objects.filter(any([Q(name__startswith=letter) for letter in 'abc']))

but I don't know how to add to it other conditions. In other words I have added to this and other filters to the same query.
July 2nd 19 at 14:05
3 answers
July 2nd 19 at 14:07
On small tables can be regularaly
Model.objects.filter(name__iregex=r'^([b-d])')
In many situations, a regex is irreplaceable, but in this case it can lead to significant performance degradation. If you are using postgresql, the query will take twice as long when you use mysql at times (because mysql can't use indexes to optimize regex). If the table is small it can be neglected, but it is better to use a more universal solution. - Hilma79 commented on July 2nd 19 at 14:10
Damn buzzkill. And I already thought - that's it nice and short solution. :( :D - kurt_Jacobson commented on July 2nd 19 at 14:13
:
Me a solution with regexp also like its brevity, but you need to understand the limits of its application. On large tables the query with a dozen likes on indexed field is executed immediately, regexp - with a noticeable delay:

like * 10:
20746 string - '0:00:00.016564'
77826 lines - '0:00:00.014466'
363406 string - '0:00:00.015869'

regexp:
20746 string - '0:00:00.072798' (4 times slower)
77826 lines - '0:00:00.154604' (10 times)
363406 string - '0:00:00.656853' (40 times)

server E5-2670 v2, 32GB
tables - InnoDB with real data

Twice the difference in performance for a loaded project are two servers instead of one, ten or ten servers. - Hilma79 commented on July 2nd 19 at 14:16
July 2nd 19 at 14:09
letters = 'ABCDE'
Model.objects.filter(reduce(
 lambda x,y: (isinstance(x, Q) and x or Q(name__istartswith=x)) | Q(name__istartswith=y), 
letters
))

# Or

from operator import or_
Model.objects.filter(
 reduce(or_, (Q(name__istartswith=l) for l in letters))
)

Deal :)
Guido van Rossum excluded the reduce function from the standard library more than 10 years ago www.artima.com/weblogs/viewpost.jsp?thread=98196 instead, you must use functools.reduce - Hilma79 commented on July 2nd 19 at 14:12
both examples will raise an exception if letters = " - kurt_Jacobson commented on July 2nd 19 at 14:15
July 2nd 19 at 14:11
import operator
import functools

from django.db.models import Q

from .models import Item


def get_items(letters="):
 items = Item.objects.filter(active=True)
 items = items.exclude(id__lt=100).exclude(id__gt=200)
 if letters:
 q = functools.reduce(operator.or_, (Q(name__istartswith=l) for l in letters))
 items = items.filter(q)
 return items

get_items('abc')


from django.db.models import Q

from .models import Item


def get_items(letters=", active=None):
 q = Q()
 if len(letters) == 3 and letters[1] == '-':
 letters = (unichr(c) for c in range(ord(letters[0]), ord(letters[2]) + 1))
 for letter in letters:
 q |= Q(name__istartswith=letter)
 if active is not None:
 q &= Q(active=active)
 return Item.objects.filter(q)

get_items(u 'ABCD')
get_items(u-d')
get_items(u a-I', True)
But there seems to get several DB queries? I have one. - Hilma79 commented on July 2nd 19 at 14:14
It won't work. And what is the meaning to rewrite my answer? - kurt_Jacobson commented on July 2nd 19 at 14:17
: I think he wanted to answer the second part of my question about how to add more filters. - Hilma79 commented on July 2nd 19 at 14:20
: .filter and went on filters hang. As always. - Hilma79 commented on July 2nd 19 at 14:23
: I just haven't had to do multiple filters at once. :D I just started to learn django... - Hilma79 commented on July 2nd 19 at 14:26
: ORM in Django "lazy" - refers to the base only at the moment when the data is required, so the request will be only a single (but with multiple conditions) - kurt_Jacobson commented on July 2nd 19 at 14:29
: 1. in the current version of python there is no reduce function, instead you need to use functools.reduce; 2. if the list of letters is empty, the reduce will throw an exception, so you need additional testing; 3. the author of the question was interested in how you can specify additional conditions in my answer to this subject is disclosed. - glennie_Mer commented on July 2nd 19 at 14:32
an example of a query that generates ORM:
>>> print Item.objects.exclude(active=False).filter(reduce(operator.or_, (Q(name__istartswith=l) for l in 'abc')))[40:60].query
SELECT `appname_item`.`id`, `appname_item`.`name`, `appname_item`.`slug`, `appname_item`.`image`, `appname_item`.`active` FROM `appname_item` WHERE (NOT (`appname_item`.`active` = False) AND (`appname_item`.`name` LIKE a% OR `appname_item`.`name` LIKE 'b% OR `appname_item`.`name` LIKE' c%)) ORDER BY `appname_item`.`name` ASC LIMIT 20 OFFSET 40 - kurt_Jacobson commented on July 2nd 19 at 14:35
:
1. from functools import reduce and she's back in scope. Imports probably every student who came in Python is almost the first thing. Just the same reduce to use a more pythonic way, rather than functools.reduce only if you have several functions called reduce used.
2. We do not consider the case when the letter list is blank, because the question is how to create a query in the DB this is a list of letters.

Again, I repeat, your example to work still not :) - glennie_Mer commented on July 2nd 19 at 14:38
:
in accordance with PEP 8 both ways of import are interchangeable - https://www.python.org/dev/peps/pep-0008/#imports but in python 2 with "from functools import reduce" will lead to a redefinition of built-in function reduce, so in this case "import functools" is the preferred method (functools.just reduce and reduce - different function)
- filter results - a typical problem, empty the filter - a typical situation, the boundary values we need to check always
- u "and went on filters hang" has a name - modification of the QuerySet
structure of the type "lambda x,y: (isinstance(x, Q) and x or Q(name__istartswith=x)) | Q(name__istartswith=y)," we need to beat the hand because it's ugly and unreadable
Don't want to waste time breeding srach in the comments and attempts by more experienced colleagues? - kurt_Jacobson commented on July 2nd 19 at 14:41
: /facepalm - Hilma79 commented on July 2nd 19 at 14:44
: like she understood your request, except for one thing - what active? What is its purpose? - Hilma79 commented on July 2nd 19 at 14:47
: active - an example of additional conditions, it is assumed that the model has a field with the same name - Hilma79 commented on July 2nd 19 at 14:50
: thought so. Then. :D - glennie_Mer commented on July 2nd 19 at 14:53

Find more questions by tags PythonDjango