我们在Django 1.9应用程序中使用了第三方库。我们想用原始应用程序中没有的一些功能来修改该应用程序(针对MongoDB)。我们目前通过我们自己的原始lib分支来实现这一点,但希望使更改更加正交,这样它们最终可能会被拉向上游。
我们已经尝试在应用程序config ready()
中进行修补,但模型导入在django.apps.registry.populate()
中的此调用之前进行处理,在__init__
中执行此操作会受到apps_ready == False
的影响。在生命周期中执行此操作的最佳部分是什么?
class MongoConfig(AppConfig):
def __init__(self, app_name, app_module):
super(MongoConfig, self).__init__(app_name, app_module)
for p in patches:
patch(*p)
def patch(old, new):
old_module, old_item = split_mod(old)
new_module, new_item = split_mod(new)
print('patching {0} with {1}'.format(old, new))
old_module = import_module(old_module)
new_module = import_module(new_module)
setattr(old_module, old_item, getattr(new_module, new_item))
我真的不喜欢monkey补丁(除了在测试用例中,即使在那时我也相信mock更好)。
你为什么不试试更简单的选择?在你的项目中创建一个应用程序的代理(由于Python的查找系统,它将首先被调用),然后简单地修补你想要的方法,并绕过你不想要的方法到原始应用程序。
因此,如果该组件名为"FooProject",您将在您的项目中创建另一个名为"FooProject"的应用程序,在该应用程序的__init__.py
:中
from originalproject import FooProject as OriginalFoo
class FooProject(OriginalFoo):
def override_method_here(self, foo):
return my_own_magic(foo)
我最终在初始化的wsgi部分完成了这项工作
在wsgi.py中
# Monkey Patch a few things
from huey_monitor.apps import HueyMonitorConfig
HueyMonitorConfig.verbose_name = 'Task Monitor'
Monkey补丁是一种破解,很难维护,应该避免。
原则是在导入代码之前,在加载Django本身之前对代码进行修补。根据你的切入点,你会找到合适的地方来修补你的代码。
使用Django 1.9,我可以考虑两个入口点:
- wsgi.py-当您的代码在wsgi容器上运行时
- manage.py-运行任何管理命令(shell、runserver、migrate)时
我只是有一个类似的需求,需要对django-allauth/django-invitation
适配器进行猴子补丁,但偶然发现了同样的限制(apps_ready == False
)。
因此,我部分使用了@domtes提到的内容,编辑manage.py
并在其中插入一个方法来部分重写我必须修改的适配器,从而附加所需的行为。当django
加载django-invitations
时,该方法已经被重写。
这是一个简单,肮脏,可能不建议搜索&replace方法,其中我重写了属于库结构的目标CCD_ 11文件。
它应该与未来的版本兼容,但我承认这是错误和问题的根源。
干杯