Можно ли фильтровать набор запросов Django по свойству модели?
у меня есть метод в моей модели:
@property
def myproperty(self):
[..]
и теперь я хочу отфильтровать это свойство, например:
MyModel.objects.filter(myproperty=[..])
это как-то возможно?
Ответы:
Неа. Фильтры Django работают на уровне базы данных, генерируя SQL. Для фильтрации на основе свойств Python вам необходимо загрузить объект в Python для оценки свойства - и к этому моменту вы уже выполнили всю работу по его загрузке.
источник
Возможно, я неправильно понимаю ваш исходный вопрос, но в python есть встроенный фильтр .
Но лучше использовать понимание списка :
filtered = [x for x in MyModel.objects if x.myproperty()]
или даже лучше, выражение генератора :
filtered = (x for x in MyModel.objects if x.myproperty())
источник
Отказавшись от предлагаемого обходного пути @ TheGrimmScientist, вы можете создать эти «свойства sql», определив их в Manager или QuerySet, и повторно использовать / связать / составить их:
С менеджером:
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/ для получения дополнительной информации. Обратите внимание, что я ухожу от документации и не тестировал вышеуказанное.
источник
Похоже, моим решением будет использование 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
затем составление списка по всем объектам.
источник
У меня была такая же проблема, и я разработал это простое решение:
objects_id = [x.id for x in MyModel.objects.all() if x.myProperty == [...]] MyModel.objects.filter(id__in=objects_id)
Я знаю, что это не самое эффективное решение, но может помочь в таких простых случаях, как мой
источник
ПОЖАЛУЙСТА, меня поправят, но я думаю, что нашел решение, по крайней мере, для моего собственного случая.
Я хочу работать со всеми теми элементами, свойства которых в точности равны ... чему угодно.
Но у меня есть несколько моделей, и эта процедура должна работать для всех моделей. И это действительно так:
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)
С помощью этой универсальной подпрограммы я могу выбрать все те элементы, которые точно соответствуют моему словарю комбинаций «указать» (имя свойства, значение свойства).
Первый параметр принимает (models.Model),
второй словарь вроде: {"property1": "77", "property2": "12"}
И он создает оператор SQL, например
SELECT * from appname_modelname WHERE property1 = '77' AND property2 = '12'
и возвращает QuerySet для этих элементов.
Это тестовая функция:
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
А также? Что вы думаете?
источник
AttributeError: 'RawQuerySet' object has no attribute 'values'
Я знаю, что это старый вопрос, но ради тех, кто здесь прыгает, я думаю, было бы полезно прочитать приведенный ниже вопрос и относительный ответ:
Как настроить фильтр администратора в Django 1.4
источник
Он также может быть возможным использовать QuerySet аннотации , которые дублируют свойство Get / Set-логику, как это было предложено , например , с помощью @rattray и @thegrimmscientist , в сочетании с
property
. Это может дать что-то, что работает как на уровне Python, так и на уровне базы данных.Однако не уверен в недостатках: см. Этот вопрос SO для примера.
источник