365đź‘Ť
Python’s argument expansion may be used to solve this problem:
kwargs = {
'{0}__{1}'.format('name', 'startswith'): 'A',
'{0}__{1}'.format('name', 'endswith'): 'Z'
}
Person.objects.filter(**kwargs)
This is a very common and useful Python idiom.
8đź‘Ť
A simplified example:
In a Django survey app, I wanted an HTML select list showing registered users. But because we have 5000 registered users, I needed a way to filter that list based on query criteria (such as just people who completed a certain workshop). In order for the survey element to be re-usable, I needed for the person creating the survey question to be able to attach those criteria to that question (don’t want to hard-code the query into the app).
The solution I came up with isn’t 100% user friendly (requires help from a tech person to create the query) but it does solve the problem. When creating the question, the editor can enter a dictionary into a custom field, e.g.:
{'is_staff':True,'last_name__startswith':'A',}
That string is stored in the database. In the view code, it comes back in as self.question.custom_query
. The value of that is a string that looks like a dictionary. We turn it back into a real dictionary with eval() and then stuff it into the queryset with **kwargs:
kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")
- [Django]-Django-rest-framework returning 403 response on POST, PUT, DELETE despite AllowAny permissions
- [Django]-How to add superuser in Django from fixture
- [Django]-Best practices for adding .gitignore file for Python projects?
7đź‘Ť
Additionally to extend on previous answer that made some requests for further code elements I am adding some working code that I am using
in my code with Q. Let’s say that I in my request it is possible to have or not filter on fields like:
publisher_id
date_from
date_until
Those fields can appear in query but they may also be missed.
This is how I am building filters based on those fields on an aggregated query that cannot be further filtered after the initial queryset execution:
# prepare filters to apply to queryset
filters = {}
if publisher_id:
filters['publisher_id'] = publisher_id
if date_from:
filters['metric_date__gte'] = date_from
if date_until:
filters['metric_date__lte'] = date_until
filter_q = Q(**filters)
queryset = Something.objects.filter(filter_q)...
Hope this helps since I’ve spent quite some time to dig this up.
Edit:
As an additional benefit, you can use lists too. For previous example, if instead of publisher_id you have a list called publisher_ids, than you could use this piece of code:
if publisher_ids:
filters['publisher_id__in'] = publisher_ids
- [Django]-How to pull a random record using Django's ORM?
- [Django]-Django admin default filter
- [Django]-Multiple ModelAdmins/views for same model in Django admin
- [Django]-Using Python's os.path, how do I go up one directory?
- [Django]-Django Rest Framework custom response message
- [Django]-How to resize an ImageField image before saving it in python Django model
0đź‘Ť
This looks much more understandable to me:
kwargs = {
'name__startswith': 'A',
'name__endswith': 'Z',
***(Add more filters here)***
}
Person.objects.filter(**kwargs)
- [Django]-Migrating Django fixtures?
- [Django]-How do I convert a Django QuerySet into list of dicts?
- [Django]-How do I install psycopg2 for Python 3.x?
-3đź‘Ť
A really complex search forms usually indicates that a simpler model is trying to dig it’s way out.
How, exactly, do you expect to get the values for the column name and operation?
Where do you get the values of 'name'
an 'startswith'
?
filter_by = '%s__%s' % ('name', 'startswith')
-
A “search” form? You’re going to — what? — pick the name from a list of names? Pick the operation from a list of operations? While open-ended, most people find this confusing and hard-to-use.
How many columns have such filters? 6? 12? 18?
- A few? A complex pick-list doesn’t make sense. A few fields and a few if-statements make sense.
- A large number? Your model doesn’t sound right. It sounds like the “field” is actually a key to a row in another table, not a column.
-
Specific filter buttons. Wait… That’s the way the Django admin works. Specific filters are turned into buttons. And the same analysis as above applies. A few filters make sense. A large number of filters usually means a kind of first normal form violation.
A lot of similar fields often means there should have been more rows and fewer fields.
- [Django]-What is pip install -q -e . for in this Travis-CI build tutorial?
- [Django]-Are Django SECRET_KEY's per instance or per app?
- [Django]-How to manage local vs production settings in Django?