Django - 调用方法的自定义过滤器

2 投票
1 回答
3776 浏览
提问于 2025-04-16 11:07

我知道不能通过过滤器来调用方法,因为过滤器是基于数据库的。所以我在尝试写一个自定义的过滤器。

    @staticmethod
    def custom_filter(obj,method_name, arg=False):
        for i in obj.objects.all():
            if getattr(i, method_name)() == arg:
                yield i

如果我这样调用的话,可以让它工作:

MyModel.custom_filter(MyModel,'my_method','myarg')

但是,我不能像普通过滤器那样把这些调用连在一起。

我可以这样做:

@staticmethod
def custom_double_filter(obj,method1,arg1,method2,arg2):
    for i in obj.objects.all():
        if getattr(i, method1)() == arg1 and getattr(i,method2)()==arg2:
            yield i

但我希望它能支持任意数量的过滤器,并且有些方法还有自己的参数。

@staticmethod
def custom_double_filter(obj,method1,arg1,method2,arg2):
    for i in obj.objects.all():
        if getattr(i, method1)(<may need to pass an argument>) == arg1 and getattr(i,method2)()==arg2:
            yield i

编辑:所以我尝试这样做一个自定义管理器:

class GroupManager(models.Manager):
    use_for_related_fields = True

    def custom_filter(self,method_name, arg=False):
        results = []
        for i in self.all():
            if getattr(i, method_name)() == arg:
                results.append(i)
        return results

这样做可以让自定义过滤器工作一次,但显然因为我返回的是一个列表,所以我不能把这些调用连在一起。我需要一种方法来传递任意数量的参数。

1 个回答

5

过滤器其实并不是你模型类的一部分。

它们是和你的模型类相关联的一个管理器的一部分。默认的管理器实例叫做 objects

不过,你可以添加一些带有特殊过滤器的管理器。

http://docs.djangoproject.com/en/1.2/topics/db/managers/

如果你自己写一个定制的管理器,记得看看这部分内容:http://docs.djangoproject.com/en/1.2/topics/db/managers/#controlling-automatic-manager-types,这样你的新管理器就能完成默认管理器的所有功能,还能加上你新添加的特殊过滤器。

我希望这个过滤器能调用任何方法或方法的组合。

这有点疯狂,但你可能能让它工作。调用“任何方法”意味着你得准备好并传入这个方法所需的所有参数。这样就涉及到太多的 *arg**kw 的元编程了,我觉得有点复杂。

我建议这个管理器不是“通用的”,而是有一些方法专门对应底层模型。你也不会叫它们 filter,而是用一种简单的方式将它们映射到模型上。

我认为简单的管理器方法对应简单的模型方法是你能做到的最好效果。

另外,你还有传统的 Python 列表推导式和生成器函数。我们会用这些。

def our_special_filter( some_queryset ):
    for row in some_queryset:
        if row.aMethod(): yield row

result= our_special_filter( SomeModel.objects.filter(...) )

是的。这打破了流畅的 API 风格。但它很简单,效果也不错。

撰写回答