在Django中创建自定义字段查找
在Django中,如何创建自定义的字段查找?
当你在过滤查询集时,Django提供了一些可以使用的查找方式,比如__contains
、__iexact
、__in
等等。我想为我的管理器提供一个新的查找方式,比如说,有人可以这样写:
twentysomethings = Person.objects.filter(age__within5=25)
这样就能得到所有年龄在20到30岁之间的Person
对象。我需要去继承QuerySet
或Manager
类才能做到这一点吗?具体应该怎么实现呢?
4 个回答
7
与其创建一个字段查找,最佳做法是创建一个管理方法,它可能看起来像这样:
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)
12
一种更灵活的方法是编写一个自定义的查询集和一个自定义的管理器。我们可以参考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)
3
从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)
这个方法。