Django에서 맞춤형 필드 조회를 만듭니다
-
18-09-2019 - |
문제
사용자 정의를 어떻게 만들 수 있습니까? 현장 조회 장고에서?
쿼리 세트를 필터링 할 때 Django는 사용할 수있는 조회 세트를 제공합니다. __contains
, __iexact
, __in
, 기타 등등. 예를 들어 누군가가 말할 수 있습니다.
twentysomethings = Person.objects.filter(age__within5=25)
그리고 모든 것을 되 찾으십시오 Person
20 세에서 30 세 사이의 물체. 서브 클래스가 필요합니까? QuerySet
또는 Manager
이 작업을 수행하는 수업? 어떻게 구현됩니까?
해결책
Django 1.7에서이를 구현하는 간단한 방법이 있습니다. 귀하의 예는 실제로의 예와 매우 유사합니다. 문서:
from django.db.models import Lookup
class AbsoluteValueLessThan(Lookup):
lookup_name = 'lt'
def as_sql(self, qn, connection):
lhs, lhs_params = qn.compile(self.lhs.lhs)
rhs, rhs_params = self.process_rhs(qn, connection)
params = lhs_params + rhs_params + lhs_params + rhs_params
return '%s < %s AND %s > -%s' % (lhs, rhs, lhs, rhs), params
AbsoluteValue.register_lookup(AbsoluteValueLessThan)
등록하는 동안 만 사용할 수 있습니다 Field.register_lookup(AbsoluteValueLessThan)
대신에.
다른 팁
보다 유연한 방법은 사용자 정의 쿼리 세트와 사용자 정의 관리자를 작성하는 것입니다. Ozan 코드에서 작업 :
class PersonQuerySet(models.query.QuerySet):
def in_age_range(self, min, max):
return self.filter(age__gte=min, age__lt=max)
class PersonManager(models.Manager):
def get_query_set(self):
return PersonQuerySet(self.model)
def __getattr__(self, name):
return getattr(self.get_query_set(), name)
class Person(models.Model):
age = #...
objects = PersonManager()
이를 통해 사용자 정의 쿼리를 체인 할 수 있습니다. 따라서이 두 쿼리는 유효합니다.
Person.objects.in_age_range(20,30)
Person.objects.exclude(somefield = some_value).in_age_range(20, 30)
필드 조회를 만드는 대신 모범 사례는 관리자 방법을 만드는 것입니다.이 방법은 다음과 같습니다.
class PersonManger(models.Manager):
def in_age_range(self, min, max):
return self.filter(age__gte=min, age__lt=max)
class Person(models.Model):
age = #...
objects = PersonManager()
그렇다면 사용법은 다음과 같습니다.
twentysomethings = Person.objects.in_age_range(20, 30)
먼저, 당신이 원하는 것을 공개적으로 촉진하기위한 Django 기계가 없다고 가정 해 봅시다.
(편집 - 실제로 Django 1.7 이후 : 다음이 있습니다. https://docs.djangoproject.com/en/1.7/howto/custom-lookups/ )
그것은 당신이라면 진짜 이것을 달성하고 싶습니다, 서브 클래스 QuerySet
그리고 _filter_or_exclude()
방법. 그런 다음 사용자 정의 만 반환하는 사용자 정의 관리자를 만듭니다. QuerySet
(또는 Monkey-Patch Django 's QuerySet
, yuck). 우리는 이것을합니다 neo4django neo4j-specific을 구축하는 동안 가능한 한 많은 Django ORM Queryset 코드를 재사용하려면 Query
사물.
Zach의 대답에서 적용된 이와 같은 (대략)를 시도하십시오. 필드 조회 구문 분석에 대한 실제 오류 처리를 독자를위한 연습으로 남겼습니다. :)
class PersonQuerySet(models.query.QuerySet):
def _filter_or_exclude(self, negate, *args, **kwargs):
cust_lookups = filter(lambda s: s[0].endswith('__within5'), kwargs.items())
for lookup in cust_lookups:
kwargs.pop(lookup[0])
lookup_prefix = lookup[0].rsplit('__',1)[0]
kwargs.update({lookup_prefix + '__gte':lookup[1]-5,
lookup_prefix + '__lt':lookup[1]+5})
return super(PersonQuerySet, self)._filter_or_exclude(negate, *args, **kwargs)
class PersonManager(models.Manager):
def get_query_set(self):
return PersonQuerySet(self.model)
class Person(models.Model):
age = #...
objects = PersonManager()
최종 비고 - 분명히, 사용자 정의 필드 조회를 체인하려면 이것은 꽤 털이 생길 것입니다. 또한, 나는 일반적으로 이것을 조금 더 기능적으로 작성하고 성능을 위해 Itertools를 사용하지만 그것을 남겨 두는 것이 더 분명하다고 생각했습니다. 재미있게 보내세요!