Django에서 동적 필드 조회로 QuerySet을 어떻게 필터링합니까?


160

주어진 수업 :

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=20)

동적 인수를 기반으로 필터링하는 QuerySet을 가질 수 있습니까? 예를 들면 다음과 같습니다.

 # Instead of:
 Person.objects.filter(name__startswith='B')
 # ... and:
 Person.objects.filter(name__endswith='B')

 # ... is there some way, given:
 filter_by = '{0}__{1}'.format('name', 'startswith')
 filter_value = 'B'

 # ... that you can run the equivalent of this?
 Person.objects.filter(filter_by=filter_value)
 # ... which will throw an exception, since `filter_by` is not
 # an attribute of `Person`.

답변:


310

파이썬의 인수 확장은이 문제를 해결하기 위해 사용될 수 있습니다 :

kwargs = {
    '{0}__{1}'.format('name', 'startswith'): 'A',
    '{0}__{1}'.format('name', 'endswith'): 'Z'
}

Person.objects.filter(**kwargs)

이것은 매우 일반적이고 유용한 파이썬 관용구입니다.


6
kwargs의 문자열이 유니 코드가 아닌 str 유형인지 확인하십시오. 그렇지 않으면 filter ()가 무너집니다.
Steve Jalim

1
@santiagobasulto 파라미터 패키징 / 패킹 해제 및 그 변형을 말합니다.
Daniel Naab

7
좋은, 좋은, 그리고 멋진 !
Oscar Mederos 23시 48 분

5
@DanielNaab 그러나 이것은 AND 조건 필터링, OR 조건에 대한 대안 인 kwargs에서만 작동합니다.
Prateek099

3
@ prateek 당신은 항상 Q 객체를 사용할 수 있습니다 : stackoverflow.com/questions/13076822/…
deecodameeko

6

간단한 예 :

Django Survey 앱에서 등록 된 사용자를 표시하는 HTML 선택 목록을 원했습니다. 그러나 등록 된 사용자가 5000 명이므로 쿼리 기준 (예 : 특정 워크샵을 완료 한 사람)을 기준으로 목록을 필터링하는 방법이 필요했습니다. 설문 조사 요소를 재사용하려면 설문 조사 질문을 작성하는 사람이 해당 기준을 해당 질문에 첨부 할 수 있어야했습니다 (쿼리를 앱에 하드 코딩하고 싶지는 않음).

내가 생각해 낸 해결책은 100 % 사용자 친화적이지 않지만 (기술 담당자의 도움을 받아 쿼리를 작성해야 함) 문제를 해결합니다. 질문을 작성할 때 편집기는 다음과 같은 사용자 정의 필드에 사전을 입력 할 수 있습니다.

{'is_staff':True,'last_name__startswith':'A',}

해당 문자열은 데이터베이스에 저장됩니다. 뷰 코드에서는로 다시 나타납니다 self.question.custom_query. 그 값은 사전처럼 보이는 문자열입니다 . eval () 을 사용하여 다시 실제 사전으로 바꾸고 ** kwargs를 사용하여 쿼리 세트에 넣습니다.

kwargs = eval(self.question.custom_query)
user_list = User.objects.filter(**kwargs).order_by("last_name")   

GUI 측에서 사용자가 기본적으로 쿼리를 "빌드"하고 실제 텍스트를 보지 않지만 인터페이스를 사용하여 그렇게하세요. 깔끔한 프로젝트처럼 들리지만 ...
T. Stone

1
T. Stone-쿼리가 필요한 모델이 단순하지만 가능한 모든 옵션을 노출시키는 철저한 방법으로, 특히 모델이 복잡한.
shacker

5
eval()사용자를 완전히 신뢰하더라도 -1 사용자 가져 오기 호출 은 나쁜 생각입니다. 여기서 JSON 필드가 더 좋습니다.
존 카터

5

Django.db.models.Q 는 Django 방식으로 원하는 것입니다.


7
동적 필드 이름을 사용할 때 Q 객체를 사용하는 방법에 대한 예를 제공 할 수 있습니까?
jackdbernier

3
Daniel Naab의 답변 과 동일합니다 . 유일한 차이점은 인수를 Q 객체 생성자로 전달한다는 것입니다. Q(**filters), Q 객체를 동적으로 빌드하려면 목록 .filter(*q_objects)에 넣고을 사용하거나 비트 연산자를 사용하여 Q 객체를 결합 할 수 있습니다.
Will S

5
이 답변에는 실제로 Q를 사용하여 OP의 문제를 해결하는 예가 포함되어야합니다.
pdoherty926

-2

매우 복잡한 검색 양식은 일반적으로 간단한 모델이 빠져 나 가려고한다는 것을 나타냅니다.

정확히 열 이름과 연산에 대한 값을 얻으려면 어떻게해야합니까? 어디의 값을받을 수 있나요 'name''startswith'?

 filter_by = '%s__%s' % ('name', 'startswith')
  1. "검색"양식? 당신은 무엇을 할 것입니까? -이름 목록에서 이름을 선택 하시겠습니까? 작업 목록에서 작업을 선택 하시겠습니까? 개방형이지만 대부분의 사람들은이 혼란스럽고 사용하기 어렵다는 것을 알게됩니다.

    이러한 필터가있는 열은 몇 개입니까? 6? 12? 18?

    • 몇? 복잡한 선택 목록은 의미가 없습니다. 몇 가지 필드와 몇 가지 if 문이 의미가 있습니다.
    • 큰 수? 모델이 제대로 들리지 않습니다. "필드"는 실제로 열이 아닌 다른 테이블의 행에 대한 열쇠 인 것 같습니다.
  2. 특정 필터 버튼. 잠깐만 ... Django 관리자가 작동하는 방식입니다. 특정 필터는 버튼으로 바뀝니다. 위와 동일한 분석이 적용됩니다. 몇 가지 필터가 의미가 있습니다. 많은 수의 필터는 일반적으로 일종의 첫 번째 일반 양식 위반을 의미합니다.

유사한 필드가 많으면 행이 많고 필드가 적어야한다는 것을 의미합니다.


9
이와 관련하여 디자인에 대해 전혀 몰라도 권장 사항을 제시하는 것은 의심의 여지가 있습니다. 이 응용 프로그램을 "간단히 구현"하려면 요구 사항을 충족하는 천문학적 기능 (> 200 개 앱 ^ 21 개 foos)이 필요합니다. 당신은 예제를 읽고 목적을 읽고 있습니다. 해서는 안됩니다. :)
Brian M. Hunt

2
나는 (a) 더 일반적이고 (b) 상상했던 방식으로 일을한다면 문제를 해결하는 것이 사소한 것이라고 생각하는 많은 사람들을 만난다. 그런 방식은 끝없는 좌절에 빠지게됩니다. 왜냐하면 그들이 상상했던 방식이 아니기 때문입니다. 너무 많은 실패가 "프레임 워크 수정"에서 비롯된 것으로 나타났습니다.
S.Lott

2
다니엘의 반응에 따라 예상대로 작동합니다. 내 질문은 디자인이 아니라 구문에 관한 것이었다. 디자인을 쓸 시간이 있다면 그렇게했을 것입니다. 귀하의 의견이 도움이 될 것이라고 확신하지만 실용적인 옵션은 아닙니다.
Brian M. Hunt

8
S.Lott, 귀하의 답변은이 질문에 원격으로 답변하지도 않습니다. 답을 모른다면 질문을 내버려 두십시오. 디자인에 대한 지식이 전혀없는 경우 원치 않는 디자인 조언으로 응답하지 마십시오!
slypete

2
@ slypete : 디자인을 변경하면 문제가 해결되면 문제가 해결됩니다. 열악한 디자인을 기반으로 경로를 계속 유지하는 것이 필요 이상으로 비싸고 복잡합니다. 잘못된 설계 결정으로 인한 다른 문제를 해결하는 것보다 근본 원인 문제를 해결하는 것이 좋습니다. 근본 원인 분석이 마음에 들지 않아서 죄송합니다. 그러나 무언가가 어려울 때는 대개 잘못된 것을 시작하려고한다는 것을 의미합니다.
S.Lott
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.