按属性过滤

148 投票
8 回答
102994 浏览
提问于 2025-04-15 13:16

可以通过模型属性来过滤Django的查询集吗?

我在我的模型里有一个方法:

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

现在我想通过这个属性来进行过滤,比如:

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

这样做有可能吗?

8 个回答

39

根据@TheGrimmScientist建议的解决方法,你可以通过在管理器(Manager)或查询集(QuerySet)上定义这些“sql属性”,然后重复使用、链接或组合它们:

使用管理器:

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)

使用查询集:

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

想了解更多,可以查看 这个链接。请注意,我是根据文档内容来讲解的,以上内容我并没有实际测试过。

59

我可能没有完全理解你最开始的问题,不过在Python里有一个叫做 filter 的内置函数。

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

不行。Django的过滤器是在数据库层面工作的,它会生成SQL语句。如果你想根据Python中的属性来过滤数据,你必须先把对象加载到Python中去评估这个属性——而在那时,你已经完成了加载数据的所有工作。

撰写回答