속성으로 필터링


95

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

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

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

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

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

어떻게 든 가능합니까?


그것은 SQLAlchemy의에 있습니다 docs.sqlalchemy.org/en/latest/orm/extensions/hybrid.html 당신은을 통해 SQLAlchemy의 장고 연결할 수 pypi.python.org/pypi/aldjemy 하지만 두 사람이 연결 될 수 있음을 의심 해요 당신이 원하는 방식으로.
rattray 2016 년

답변:


78

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


5
이 기능이 구현되지 않은 불운 은 결과 집합이 빌드 된 적어도 일치하는 개체를 필터링하는 흥미로운 확장 기능이 될 것 입니다.
schneck

1
관리자에서 처리하는 방법? 해결 방법이 있습니까?
andilabs 2014

39

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

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())

15
Python 객체가 있으면 필터링이 작동하지만 SQL 쿼리를 생성하는 Django QuerySet.filter에 대해 묻습니다.
Glenn Maynard

1
맞지만 위에서 설명한대로 데이터베이스 필터에 속성을 추가하고 싶습니다. 쿼리가 완료된 후 필터링은 정확히 내가 피하고 싶은 것입니다.
schneck

19

@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/ 를 참조 하십시오 . 문서에서 벗어나 위의 내용을 테스트하지 않았습니다.


14

주석과 함께 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

그런 다음 모든 개체에 대해 목록 이해를 수행합니다.


5

나는 같은 문제가 있었고 다음과 같은 간단한 해결책을 개발했습니다.

objects_id = [x.id for x in MyModel.objects.all() if x.myProperty == [...]]
MyModel.objects.filter(id__in=objects_id)

가장 성능이 좋은 솔루션은 아니지만 간단한 경우에는 도움이 될 수 있습니다.


3

누군가 나를 정정하십시오. 그러나 적어도 내 경우에는 해결책을 찾은 것 같습니다.

나는 속성이 정확히 같은 모든 요소에 대해 작업하고 싶습니다.

하지만 여러 모델이 있고이 루틴은 모든 모델에서 작동합니다. 그리고 그것은합니다 :

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 

과? 어떻게 생각해?


일반적으로 괜찮은 해결 방법처럼 보입니다. 이상적이라고 말하지는 않겠지 만, 이와 같은 것이 필요할 때마다 PyPI에서 설치 한 패키지의 모델을 수정하기 위해 저장소를 포크해야하는 것보다 낫습니다.
hlongmore

그리고 이제 조금 놀아 볼 시간이 생겼습니다.이 접근 방식의 진짜 단점은 .raw ()에 의해 반환 된 쿼리 셋이 완전한 쿼리 셋이 아니라는 것입니다. 즉, 누락 된 쿼리 셋 메서드가 있습니다.AttributeError: 'RawQuerySet' object has no attribute 'values'
hlongmore

1

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

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


1
이 답변을 훑어 보는 사람들을 위해-이 링크는 "SimpleListFilter"를 사용하여 Django 관리자에서 목록 필터를 구현하는 방법에 대한 정보입니다. 유용하지만 매우 특정한 경우를 제외하고는 질문에 대한 답변이 아닙니다.
jenniwren

0

@rattray가 제안한 것처럼 get / set-logic 속성을 복제하는 쿼리 셋 주석을 사용할 수도 있습니다.@thegrimmscientist , 와 함께property . 이것은 파이썬 수준 데이터베이스 수준에서 모두 작동하는 것을 산출 할 수 있습니다.

그러나 단점에 대해서는 확실하지 않습니다. . 예를 들어이 SO 질문 을 .


코드 검토 질문 링크는 작성자가 자발적으로 제거했다는 알림을 제공합니다. 여기에서 코드 링크 나 설명을 사용하여 답변을 업데이트 하시겠습니까? 아니면 답변을 삭제 하시겠습니까?
hlongmore

@hlongmore : 죄송합니다. 그 질문은 SO로 옮겨졌습니다. 위의 링크를 수정했습니다.
djvg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.