10👍
filter()
operates on the database level (it actually writes SQL), so it won’t be possible to use it for any queries based on your python code (dynamic property in your question)
.
This is an answer put together from many other answers in this department : )
13👍
The accepted answer is not entirely true.
For many cases, you can override get()
in the model manager to pop
dynamic properties from the keyword arguments, then add the actual attributes you want to query against into the kwargs
keyword arguments dictionary. Be sure to return a super
so any regular get()
calls return the expected result.
I’m only pasting my own solution, but for the __startswith
and other conditional queries you could add some logic to split
the double-underscore and handle appropriately.
Here was my work-around to allow querying by a dynamic property:
class BorrowerManager(models.Manager):
def get(self, *args, **kwargs):
full_name = kwargs.pop('full_name', None)
# Override #1) Query by dynamic property 'full_name'
if full_name:
names = full_name_to_dict(full_name)
kwargs = dict(kwargs.items() + names.items())
return super(BorrowerManager, self).get(*args, **kwargs)
In models.py:
class Borrower(models.Model):
objects = BorrowerManager()
first_name = models.CharField(null=False, max_length=30)
middle_name = models.CharField(null=True, max_length=30)
last_name = models.CharField(null=False, max_length=30)
created = models.DateField(auto_now_add=True)
In utils.py (for the sake of context):
def full_name_to_dict(full_name):
ret = dict()
values = full_name.split(' ')
if len(values) == 1:
raise NotImplementedError("Not enough names to unpack from full_name")
elif len(values) == 2:
ret['first_name'] = values[0]
ret['middle_name'] = None
ret['last_name'] = values[1]
return ret
elif len(values) >= 3:
ret['first_name'] = values[0]
ret['middle_name'] = values[1:len(values)-1]
ret['last_name'] = values[len(values)-1]
return ret
raise NotImplementedError("Error unpacking full_name to first, middle, last names")
- How can I get all the objects in a Django model that have a specific value for a ForeignKey field?
- Python-social-auth with Django: ImportError: No module named 'social_django'
- Python – Django: Streaming video/mp4 file using HttpResponse
- Set DatetimeField format of django rest framework configuration
- Django: How to add an extra form to a formset after it has been constructed?
4👍
I had a similar problem and was looking for solution. Taking for granted that a search engine would be the best option (e.g. django-haystack
with Elasticsearch
), that’s how I would implement some code for your needs using only the Django ORM (you can replace icontains
with istartswith
):
from django.db.models import Value
from django.db.models.functions import Concat
queryset = User.objects.annotate(full_name=Concat('first_name', Value(' '), 'last_name')
return queryset.filter(full_name__icontains=value)
In my case I didn’t know whether the user would insert ‘first_name
last_name
‘ or viceversa, so I used the following code.
from django.db.models import Q, Value
from django.db.models.functions import Concat
queryset = User.objects.annotate(first_last=Concat('first_name', Value(' '), 'last_name'), last_first=Concat('last_name', Value(' '), 'first_name'))
return queryset.filter(Q(first_last__icontains=value) | Q(last_first__icontains=value))
With Django <1.8, you would probably need to resort to extra
with the SQL CONCAT
function, something like the following:
queryset.extra(where=['UPPER(CONCAT("auth_user"."last_name", \' \', "auth_user"."first_name")) LIKE UPPER(%s) OR UPPER(CONCAT("auth_user"."first_name", \' \', "auth_user"."last_name")) LIKE UPPER(%s)'], params=['%'+value+'%', '%'+value+'%'])
- Django Rest Framework override model fields in modelserialzer
- Django South Error: "there is no enabled application matching 'myapp'"
- List fields present in a table
- Include template tag not working in django
- Heroku/python failed to detect set buildpack
0👍
Think it’s not possible in django to filter on properties that does not present as a database filed, but what you can do to make cool autocomplete search is something like this:
if ' ' in query:
query = query.split()
search_results = list(chain(User.objects.filter(first_name__icontains=query[0],last_name__icontains=query[1]),
User.objects.filter(first_name__icontains=query[1],last_name__icontains=query[0])))
else:
search_results = User.objects.filter(Q(first_name__icontains=query)| Q(last_name__icontains=query))
This code gives the user of your system a flexibility to start typing either first name or last name and the user will be thankful to you for allowing this.