对于我的项目,我需要动态创建自定义(Class)方法。
我发现在Python中并不容易:
class UserFilter(django_filters.FilterSet):
'''
This filter is used in the API
'''
# legacy below, this has to be added dynamically
#is_field_type1 = MethodFilter(action='filter_field_type1')
#def filter_field_type1(self, queryset, value):
# return queryset.filter(related_field__field_type1=value)
class Meta:
model = get_user_model()
fields = []
但它给了我错误(和头痛......)。这甚至可能吗?
我尝试在#legacy dynamic
之间创建代码我发现这样做的一个选择是动态创建类
def create_filter_dict():
new_dict = {}
for field in list_of_fields:
def func(queryset, value):
_filter = {'stableuser__'+field:value}
return queryset.filter(**_filter)
new_dict.update({'filter_'+field: func})
new_dict.update({'is_'+field: MethodFilter(action='filter_'+field)})
return new_dict
meta_model_dict = {'model': get_user_model(), 'fields':[]}
meta_type = type('Meta',(), meta_model_dict)
filter_dict = create_filter_dict()
filter_dict['Meta'] = meta_type
UserFilter = type('UserFilter', (django_filters.FilterSet,), filter_dict)
然而,这是给了我
TypeError at /api/v2/users/
func() takes 2 positional arguments but 3 were given
有谁知道如何解决这个难题?
答案 0 :(得分:1)
例外值:' UserFilter'对象没有属性' is_bound'
您收到此错误是因为您生成的类方法未绑定到任何类。要将它们绑定到类,您需要使用setattr()
在控制台上试试这个:
class MyClass(object):
pass
@classmethod
def unbound(cls):
print "Now I'm bound to ", cls
print unbound
setattr(MyClass, "bound", unbound)
print MyClass.bound
print MyClass.bound()
回溯: UserFilter = type(' Foo',(django_filters.FilterSet,),create_filter_dict()。update({' Meta':type(' Meta',(), {'模型&#39 ;: get_user_model(),' fields':[]})}))TypeError:type()参数3必须 是dict,而不是没有
现在,这是失败的,因为dict.update()没有返回相同的实例,返回None。这很容易修复
class_dict = create_filter_dict()
class_dict.update({'Meta':type('Meta',(), {'model': get_user_model(), 'fields':[]})}
UserFilter = type('Foo', (django_filters.FilterSet, ), class_dict))
然而,看看代码看起来有多乱。我建议你尝试做 使用您编写的代码更清晰,即使它需要写一些额外的行。从长远来看,代码将更易于为您和您的团队维护。
meta_model_dict = {'model': get_user_model(), 'fields':[]}
meta_type = type('Meta',(), meta_model_dict)
filter_dict = create_filter_dict()
filter_dict['Meta'] = meta_type
UserFilter = type('Foo', (django_filters.FilterSet,), filter_dict)
此代码可能不完美,但它比您发布的原始代码行更具可读性:
UserFilter = type('Foo', (django_filters.FilterSet, ), create_filter_dict().update({'Meta':type('Meta',(), {'model': get_user_model(), 'fields':[]})}))
并消除了一个已经有点难以理解的概念的复杂性。
您可能想了解元类。也许你可以覆盖一个类的 new 方法。我可以向您推荐1或2个帖子。
另一种选择是,你可能没有正确地添加过滤器或django没有预料到的方式?这可以解释为什么你没有错误,但没有任何函数被调用。
答案 1 :(得分:0)
您可以使用classmethod。以下是如何使用它的示例:
class UserFilter:
@classmethod
def filter_field(cls, queryset, value, field = None):
# do somthing
return "{0} ==> {1} {2}".format(field, queryset, value)
@classmethod
def init(cls,list_of_fields ):
for field in list_of_fields:
ff = lambda cls, queryset, value, field=field: cls.filter_field(queryset, value, field )
setattr(cls, 'filter_'+field, classmethod( ff ))
UserFilter.init( ['a','b'] )
print(UserFilter.filter_a(1,2)) # a ==> 1 2
print(UserFilter.filter_b(3,4)) # b ==> 3 4
答案 2 :(得分:0)
你要求:
自定义(类)方法。
因此我们采用一个现有的类并派生一个子类,您可以在其中添加新方法或覆盖原始现有类的方法(查看所需方法的原始类的代码),如下所示:
from universe import World
class NewEarth(World.Earth):
def newDirectionUpsideDown(self,direction):
self.rotationDirection = direction
World.Earth的所有其他方法和功能仅适用于NewEarth,您现在可以改变方向,让世界转向新的方向。
要覆盖类的现有方法就像这样容易。
class NewEarth(World.Earth):
def leIitRain(self,amount): # let's assume leIitRain() is a standard-function of our world
return self.asteroidStorm(amount) #let's assume this is possible Method of World.Earth
所以,如果有人喜欢在地球上淋浴,那么他/她就可以在玩具大理石上以新的发展方式腾出空间。
所以学习python的方式很有趣 - 而且不要从复杂的事情开始。
如果我弄错了你 - 你可以更详细地解释你的问题 - 所以比我更聪明的人可以分享他们的智慧。