Фильтр по свойству


можно ли фильтровать по свойству?

у меня есть метод в моей модели:

@property
def myproperty(self):
    [..]

и теперь я хочу фильтровать по этому свойству, как:

MyModel.objects.filter(myproperty=[..])

это как-то возможно?

6 62

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 

и? А ты как думаешь?

Я знаю, что это старый вопрос, но ради тех, кто прыгает здесь, я думаю, что полезно прочитать вопрос ниже и относительный ответ:

как настроить фильтр администратора в Django 1.4