[python] 속성으로 필터링

모델 속성으로 Django 쿼리 셋을 필터링 할 수 있습니까?

내 모델에 방법이 있습니다.

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

이제 다음과 같이이 속성으로 필터링하고 싶습니다.

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

어떻게 든 가능합니까?



답변

아니. Django 필터는 데이터베이스 수준에서 작동하여 SQL을 생성합니다. Python 속성을 기반으로 필터링하려면 속성을 평가하기 위해 개체를 Python으로로드해야합니다.이 시점에서 이미로드 작업을 모두 완료했습니다.


답변

원래 질문을 오해하고 있을지 모르지만 파이썬 에는 필터가 내장되어 있습니다.

filtered = filter(myproperty, MyModel.objects)

그러나 목록 이해 를 사용하는 것이 좋습니다 .

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객체가 파이썬으로 가져 오기 전에 databse와 대화하기 . 그러나 속성 별 필터링을 원하는 이유는 두 개의 다른 필드에 대한 간단한 산술 결과로 객체를 필터링하기를 원했기 때문에 여전히 여기에 대답을 넣었습니다.

따라서 다음과 같은 내용이 있습니다.

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)

이 범용 서브 루틴을 사용하여 ‘지정'(propertyname, propertyvalue) 조합의 사전과 정확히 일치하는 모든 요소를 ​​선택할 수 있습니다.

첫 번째 매개 변수는 (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 

과? 어떻게 생각해?


답변

나는 그것이 오래된 질문이라는 것을 알고 있지만 여기에서 점프하는 사람들을 위해 아래 질문과 상대적인 대답을 읽는 것이 유용하다고 생각합니다.

Django 1.4에서 관리자 필터를 사용자 지정하는 방법