使用OOP我想做一些类似的事情
from django.contrib import admin
class NavigateFormAdmin(admin.ModelAdmin):
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
context['next_record_id'] = custom_function_to_calculate(context['obj'].id)
res = super().render_change_form(request, context, add, change, form_url)
return res
并且期望每当admin.ModelAdmin
的render_change_form
被调用时,它应该首先调用我的重写方法(上面),然后调用原始(父)方法。但是这没有什么区别,因为我的重写方法从来没有被调用过,而是在任何对render_change_form
的调用中调用原始类admin.ModelAdmin
的方法。
使用不需要的monkey修补
我能够实现我所需要的,通过添加以下代码到任何我的py文件,在我的项目/服务执行开始时由解释器读取
from django.contrib import admin
from django.template.response import TemplateResponse
# and also all the other imports used in original medthod
class NavigateFormAdmin(admin.ModelAdmin):
def render_change_form(self, request, context, add=False, change=False, form_url='', obj=None):
opts = self.model._meta
app_label = opts.app_label
preserved_filters = self.get_preserved_filters(request)
# and all the code of existing function has to be repeated here
context['next_record_id'] = custom_function_to_calculate(context['obj'].id)
res = TemplateResponse(request, form_template, context)
return res
admin.ModelAdmin.render_change_form = NavigateFormAdmin.render_change_form
现在,在每次调用admin.ModelAdmin.render_change_form
时,都会执行NavigateFormAdmin.render_change_form
但是我需要使用super()
(第一段代码不工作),因为OOP意味着可重用性,所以我可以实现的并不令人满意,因为原始方法的所有50行代码都重复到只有一行用于覆盖。而且这种重复的代码导致了admin.ModelAdmin
更改版本的一些意外结果
1条答案
按热度按时间oalqel3c1#
你可以像你预期的那样使用
super()
和monkey patch,虽然你不能只对单个方法进行monkey patch,但是你必须用你的新子类修补整个对象。因为你没有包括你遇到的错误,我假设你可能看到了一个关于super
的TypeError
异常。对于最小的演示,我们需要两个模块,如下所示:
a.py
b.py
作为示范:
现在,如果要导入
b
,则会应用monkey补丁:请注意,子类
B
可以简单地使用super()
来引用其父类,即使它不再被分配给a.A
-底层类层次结构被维护,B
内部的super()
将做正确的事情。然而,在实际的猴子补丁示例中,您试图重新绑定一个特定的方法-这实际上不会起作用,因为在类块内重新分配函数将导致新函数成为类定义的一部分。
将有效地导致
A
类看起来像下面的定义(实际上并不是这样,细节比这个插图 * 复杂得多 *,但大致说明了您可能遇到的问题):假设
A
没有任何子类,它不能像那样调用super()
,调用A().render(...)
将导致异常(具体细节取决于render方法的实际定义和分配)。所以简而言之,你可以使用你想要做的原始代码,并对整个类进行猴子补丁,即通过执行以下操作:
请注意,如果您的更改与原始包及其依赖项/从属项的底层预期不兼容,猴子修补可能会有自己的陷阱。