Фильтр по свойству
можно ли фильтровать по свойству?
у меня есть метод в моей модели:
@property
def myproperty(self):
[..]
и теперь я хочу фильтровать по этому свойству, как:
MyModel.objects.filter(myproperty=[..])
это как-то возможно?
6 ответов:
Неа. Фильтры Django работают на уровне базы данных, генерируя SQL. Чтобы фильтровать на основе свойств Python, вам нужно загрузить объект в Python для оценки свойства-и в этот момент вы уже выполнили всю работу по его загрузке.
возможно, я неправильно понял ваш первоначальный вопрос, но есть фильтр встроенный в python.
filtered = filter(myproperty, MyModel.objects)
но лучше использовать понимание:
filtered = [x for x in MyModel.objects if x.myproperty()]
или даже лучше, a выражение генератор:
filtered = (x for x in MyModel.objects if x.myproperty())
выглядит так: использование F () с аннотациями будет мое решение для этого.
он не будет фильтровать по
@property
СF
разговаривает с базой данных, прежде чем объекты будут введены в python. Но все же поставив его здесь в качестве ответа, так как моя причина для того, чтобы фильтровать по свойству, действительно хотела фильтровать объекты по результату простой арифметики на двух разных полях.Итак, что-то вроде:
companies = Company.objects\ .annotate(chairs_needed=F('num_employees') - F('num_chairs'))\ .filter(chairs_needed__lt=4)
а не определение свойства должно быть:
@property def chairs_needed(self): return self.num_employees - self.num_chairs
затем выполнение понимания списка по всем объектам.
Riffing off @ thegrimmscientist предложил обходной путь, вы можете сделать эти "свойства sql", определив их в Диспетчере или QuerySet, и повторно использовать / chain / compose их:
менеджер:
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)
С помощью 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()
см.https://docs.djangoproject.com/en/1.9/topics/db/managers/ для большего. Обратите внимание, что я выхожу из документации и не проверял вышеизложенное.
пожалуйста, кто-нибудь поправьте меня, но я думаю, что я нашел решение, по крайней мере для моего собственного случая.
Я хочу работать на всех тех элементах, свойства которых точно равны ... что угодно.
но у меня есть несколько моделей, и эта процедура должна работать для всех моделей. И он делает:
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)
С помощью этой универсальной подпрограммы я могу выбрать все те элементы, которые точно равны моему словарю "указать" (propertyname, propertyvalue) сочетания.
первый параметр принимает a (модели.Модель),
второй словарь, как: {"property1": "77", "property2": "12"}
и он создает оператор SQL, как
SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12'
и возвращает запрос на эти элементы.
Это тестовая функция:
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
и? А ты как думаешь?