121👍
Nope. Django filters operate at the database level, generating SQL. To filter based on Python properties, you have to load the object into Python to evaluate the property–and at that point, you’ve already done all the work to load it.
59👍
I might be misunderstanding your original question, but there is a filter builtin in python.
filtered = filter(myproperty, MyModel.objects)
But it’s better to use a list comprehension:
filtered = [x for x in MyModel.objects if x.myproperty()]
or even better, a generator expression:
filtered = (x for x in MyModel.objects if x.myproperty())
- [Django]-How to completely dump the data for Django-CMS
- [Django]-Using Django time/date widgets in custom form
- [Django]-Factory-boy create a list of SubFactory for a Factory
37👍
Riffing off @TheGrimmScientist’s suggested workaround, you can make these “sql properties” by defining them on the Manager or the QuerySet, and reuse/chain/compose them:
With a Manager:
class CompanyManager(models.Manager):
def with_chairs_needed(self):
return self.annotate(chairs_needed=F('num_employees') - F('num_chairs'))
class Company(models.Model):
# ...
objects = CompanyManager()
Company.objects.with_chairs_needed().filter(chairs_needed__lt=4)
With a QuerySet:
class CompanyQuerySet(models.QuerySet):
def many_employees(self, n=50):
return self.filter(num_employees__gte=n)
def needs_fewer_chairs_than(self, n=5):
return self.with_chairs_needed().filter(chairs_needed__lt=n)
def with_chairs_needed(self):
return self.annotate(chairs_needed=F('num_employees') - F('num_chairs'))
class Company(models.Model):
# ...
objects = CompanyQuerySet.as_manager()
Company.objects.needs_fewer_chairs_than(4).many_employees()
See https://docs.djangoproject.com/en/1.9/topics/db/managers/ for more.
Note that I am going off the documentation and have not tested the above.
- [Django]-Pagination in Django-Rest-Framework using API-View
- [Django]-What does on_delete do on Django models?
- [Django]-Django optional URL parameters
20👍
Looks like using F() with annotations will be my solution to this.
It’s not going to filter by @property
, since F
talks to the databse before objects are brought into python. But still putting it here as an answer since my reason for wanting filter by property was really wanting to filter objects by the result of simple arithmetic on two different fields.
so, something along the lines of:
companies = Company.objects\
.annotate(chairs_needed=F('num_employees') - F('num_chairs'))\
.filter(chairs_needed__lt=4)
rather than defining the property to be:
@property
def chairs_needed(self):
return self.num_employees - self.num_chairs
then doing a list comprehension across all objects.
- [Django]-Cron and virtualenv
- [Django]-What are the differences between django-tastypie and djangorestframework?
- [Django]-How to automate createsuperuser on django?
15👍
I had the same problem, and I developed this simple solution:
objects = [
my_object
for my_object in MyModel.objects.all()
if my_object.myProperty == [...]
]
This is not a performatic solution, it shouldn’t be done in tables that contains a large amount of data. This is great for a simple solution or for a personal small project.
- [Django]-(13: Permission denied) while connecting to upstream:[nginx]
- [Django]-How to convert JSON data into a Python object?
- [Django]-Django Passing Custom Form Parameters to Formset
3👍
PLEASE someone correct me, but I guess I have found a solution, at least for my own case.
I want to work on all those elements whose properties are exactly equal to … whatever.
But I have several models, and this routine should work for all models. And it does:
def selectByProperties(modelType, specify):
clause = "SELECT * from %s" % modelType._meta.db_table
if len(specify) > 0:
clause += " WHERE "
for field, eqvalue in specify.items():
clause += "%s = '%s' AND " % (field, eqvalue)
clause = clause [:-5] # remove last AND
print clause
return modelType.objects.raw(clause)
With this universal subroutine, I can select all those elements which exactly equal my dictionary of ‘specify’ (propertyname,propertyvalue) combinations.
The first parameter takes a (models.Model),
the second a dictionary like:
{“property1” : “77” , “property2” : “12”}
And it creates an SQL statement like
SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12'
and returns a QuerySet on those elements.
This is a test function:
from myApp.models import myModel
def testSelectByProperties ():
specify = {"property1" : "77" , "property2" : "12"}
subset = selectByProperties(myModel, specify)
nameField = "property0"
## checking if that is what I expected:
for i in subset:
print i.__dict__[nameField],
for j in specify.keys():
print i.__dict__[j],
print
And? What do you think?
- [Django]-On Heroku, is there danger in a Django syncdb / South migrate after the instance has already restarted with changed model code?
- [Django]-How does django handle multiple memcached servers?
- [Django]-Django-debug-toolbar not showing up
2👍
i know it is an old question, but for the sake of those jumping here i think it is useful to read the question below and the relative answer:
- [Django]-Bypass confirmation prompt for pip uninstall
- [Django]-UUID as default value in Django model
- [Django]-Django content-type : how do I get an object?
0👍
It may also be possible to use queryset annotations that duplicate the property get/set-logic, as suggested e.g. by @rattray and @thegrimmscientist, in conjunction with the property
. This could yield something that works both on the Python level and on the database level.
Not sure about the drawbacks, however: see this SO question for an example.
- [Django]-H14 error in heroku – "no web processes running"
- [Django]-Django Passing Custom Form Parameters to Formset
- [Django]-Inline in ModelForm