Python 在Django中创建自定义字段查找

Python 在Django中创建自定义字段查找,python,django,django-queryset,Python,Django,Django Queryset,如何在Django中创建自定义 过滤查询集时,django提供了一组可供使用的查找:\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。我希望能够为我的经理提供新的查找,例如,有人可能会说: twentysomethings = Person.objects.filter(age__within5=25) 并取回所有年龄在20到30岁之间的人物品。我是否需

如何在Django中创建自定义

过滤查询集时,django提供了一组可供使用的查找:
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。我希望能够为我的经理提供新的查找,例如,有人可能会说:

twentysomethings = Person.objects.filter(age__within5=25)

并取回所有年龄在20到30岁之间的
物品。我是否需要为
QuerySet
Manager
类创建子类来完成此操作?如何实现它?

最佳做法是创建一个管理器方法,而不是创建一个字段查找,它可能看起来有点像这样:

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)

更灵活的方法是编写自定义查询集和自定义管理器。根据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)

首先,我要说的是,没有Django机制是为了公开促进你想要的东西

(编辑-实际上从Django 1.7开始就有:)

这就是说,如果您真的想实现这一点,可以创建子类
QuerySet
并重写
\u filter\u或
方法。然后创建一个只返回自定义
QuerySet
(或monkey patch Django的
QuerySet
,恶心)的自定义管理器。我们这样做是为了在构建特定于Neo4j的
Query
对象时尽可能多地重用Django ORM queryset代码

试着(粗略地)这样做,根据扎克的答案改编。我将字段查找解析的实际错误处理留给读者作为练习:)


最后一句话——很明显,如果您想链接自定义字段查找,这将变得非常棘手。另外,我通常会从功能上写这篇文章,并使用itertools来提高性能,但我认为更清楚的是不使用它。玩得开心

从Django 1.7开始,有一种简单的方法可以实现它。您的示例实际上与以下示例非常相似:

从django.db.models导入查找
类绝对值小于(查找):
查找\u名称='lt'
def as_sql(自身、qn、连接):
lhs,lhs_params=qn.compile(self.lhs.lhs)
rhs,rhs_参数=自处理(qn,连接)
参数=lhs_参数+rhs_参数+lhs_参数+rhs_参数
返回“%s<%s和%s>-%s%”(左、右、左、右),参数
绝对值。寄存器查找(绝对值小于sthan)

注册时,您可以只使用
字段。注册\u查找(绝对值小于)

太好了!我仍然希望有一些API可以连接到查找字段语法,以利用rlationship遍历逻辑。我会继续挖。同时,我认为这让我更进一步了解这些碎片是如何结合在一起的。谢谢你可以更容易/更干净地使用。看起来它已经有一段时间没有更新了,但我已经使用它很多年了,从来没有遇到过任何问题。这些答案对他的例子很有用(可能是,也可能不是他为了表明自己的观点而抛出的东西)。。但我希望有人能回答实际提出的问题。@royal我想我的回答涵盖了这一点-我在一个图书馆里找到了这个。谢谢,伙计,这很有帮助。刚刚找到了你的答案!非常感谢。这就是我要找的。我应该在哪个文件中执行此操作?@user1735921已记不得了。在模型里怎么样。py?嘿,伙计,你能检查一下我的问题吗:,没有人能解决它
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()
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)