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

JPC*_*JPC 2 python django django-models

我知道你不能使用过滤器来调用方法,因为它是基于数据库来实现的.所以我正在尝试编写自定义过滤器.

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

如果我打电话,我可以让它工作:

MyModel.custom_filter(MyModel,'my_method','myarg')
Run Code Online (Sandbox Code Playgroud)

但是,我不能像常规过滤器那样将它们链接在一起.

我可以这样做:

@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
Run Code Online (Sandbox Code Playgroud)

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

@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
Run Code Online (Sandbox Code Playgroud)

编辑:所以我试着像这样制作一个自定义管理器:

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
Run Code Online (Sandbox Code Playgroud)

这适用于对custom_filter的一次调用,但很明显,因为我正在返回一个列表,所以我无法将这些调用链接在一起.我需要一种能够传递任意数量参数的方法

S.L*_*ott 5

过滤器实际上不是模型类的一部分.

它们是与您的Model类关联的Manager的一部分.默认管理器实例已命名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(...) )
Run Code Online (Sandbox Code Playgroud)

是.它打破了漂亮流畅的API风格.但它很简单,效果很好.