我想覆盖一个类方法,而不是从类创建子类/扩展。
一个例子:
from django.contrib import admin
class NewModelAdmin(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
# some custom stuff
现在我不想更改从admin.ModelAdmin
到NewModelAdmin
的所有类(又称模型)。但我也不想修改原来的django代码。
有没有办法实现这个目标?
答案 0 :(得分:4)
我不是100%清楚你想做什么,为什么你不想创建一个新的子类或者有一个不同名称的方法。
但是通常在python中你可以做类似的事情:
class MyClass(object):
def print_hello(self):
print "not hello"
def real_print_hello():
print "hello"
x = MyClass()
x.print_hello() # "not hello"
setattr(x, "print_hello", real_print_hello)
x.print_hello() # "hello"
答案 1 :(得分:3)
答案 2 :(得分:3)
为了保持代码的可维护性,最好继续使用NewModelAdmin继承您的各个ModelAdmin类。这样,查看代码的其他开发人员(以及您,也许一两年后)可以清楚地看到自定义formfield_for_dbfield行为的来源,以便在需要时可以更新。如果你修补admin.ModelAdmin,它将使得追踪问题或在以后需要时改变行为变得更加困难。
答案 3 :(得分:2)
如果没有猴子修补,你的问题是可以解决的,这很有可能,这往往会产生意想不到的后果。
您如何使用django admin注册模型?
如果您使用这种方法:
admin.site.register(FooModel) #uses generic ModelAdmin
您遇到的问题是需要将此更改为NewModelAdmin子类的许多样板实例,如下所示:
class FooModelAdmin(NewModelAdmin):
pass #does nothing except set up inheritance
admin.site.register(FooModel, FooModelAdmin)
这真的很冗长,如果你有很多模型可能需要花费很多时间来实现,所以通过编写包装函数以编程方式实现它:
def my_admin_register(model):
class _newmodeladmin(ModelAdmin):
def your_overridden_method(*args, **kwargs):
#do whatever here
admin.site.register(model, _newmodeladmin)
然后,您可以像这样使用:
my_admin_register(FooModel)
答案 4 :(得分:1)
您可以使用类setattr()
上的monkey patching
更改类方法。
答案 5 :(得分:0)
如果修改类中的方法,则修改以下行为:
您的要求是互相排斥的。您不能在不影响将其方法解析为类的对象的情况下修改类的行为。
为了不修改这些其他对象的行为,您需要创建 实例中的方法,以便它不会解决它在课堂上的方法。
另一种选择是依赖Python的鸭子打字。您不需要将对象与当前使用的对象直接相关。您可以重新实现界面,并在代码中交换旧类的调用。
这些技术在可维护性和设计方面存在权衡。换句话说,除非你没有其他选择,否则不要使用它们。
答案 6 :(得分:0)
我不是100%肯定你想要实现的目标,但我想你想要表现所有继承自models.ModelAdmin
的管理员,而不必改变他们的声明。实现这一目标的唯一解决方案是对原始ModelAdmin
类进行猴子修补,例如。类似的东西:
setattr(admin.ModelAdmin, 'form_field_for_dbfield', mymethod)
这肯定不是最值得推荐的方式,因为代码很难维护和其他东西。