在另一个应用程序中修补Django应用程序

13
我们有一个第三方库,我们在Django 1.9应用程序中使用它。 我们希望通过一些原始应用程序中没有的功能(针对MongoDB),修改该应用程序。 我们目前通过我们自己的原始库进行此操作,但希望使更改有点更加正交,以便最终可能将它们拆分上游。
我们尝试在应用程序config ready()期间打补丁,但是模型导入在django.app.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))

2
我已经在应用程序的__init__.pyAppConfig.ready回调中都实现了补丁。我不知道有人怎么能给你一个不纯粹猜测的答案。什么方法适用于哪里取决于您在问题中没有提供的细节。 - Louis
我们正在将一个现有的应用程序(django-allauth)适配到MongoDB上。这需要对模型、视图和表单进行更改,我们试图保持其与原始库正交。您还需要哪些信息? - mwjackson
4个回答

1
我很不赞成猴子补丁(除了在测试用例中,即使在这种情况下,我认为模拟是更好的选择)。
为什么不尝试更简单的选项呢?在您的项目中创建应用程序的代理(由于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)

当我评论这个问题时,我忘了提到这种可能性。我曾经用它来解决cmsplugin-iframe的限制。这种方法比猴子补丁更可取,但确实存在以下情况:a)只有猴子补丁才能起作用,或者b)猴子补丁可以提供一个更简单的解决方案。我曾经遇到过这样的情况,需要为每个已安装的应用程序创建一个代理:超过20个代理。OP没有给我们提供解决他们特定问题的最佳方法。 - Louis
我们试图修改的应用程序相当庞大(django-allauth)。除非我漏掉了什么,否则这种方法实际上是不可行的,因为我们需要修补模型、表单和视图,它们之间都有相互引用的导入语句,这些也需要更新。 - mwjackson
@mwjackson,你最终采用了哪种解决方案?因为我正在处理与OP发布的相同问题,并尝试根据最佳实践进行决策。 - Gustavo_fringe

1

我最终在初始化的wsgi部分完成了这个。

在wsgi.py中

# Monkey Patch a few things
from huey_monitor.apps import HueyMonitorConfig
HueyMonitorConfig.verbose_name = 'Task Monitor'

0

我最近也遇到类似的需求,需要对django-allauth/django-invitation的适配器进行猴子补丁,但遇到了同样的限制(apps_ready == False)。

所以我部分地使用了 @domtes 提到的方法,编辑了 manage.py 并在其中插入了一个方法来部分重写我需要修改的适配器,并附加所需的行为。当 django 加载 django-invitations 时,该方法已经被重写。

这是一种简单、粗暴且可能不推荐的搜索和替换方法,其中我重写了属于库结构的目标.py文件。

它应该兼容未来的版本,但我承认它是产生 bug 和问题的来源。

干杯!


0

猴子补丁是一种黑客技巧,难以维护,应该避免使用。

原则上,在Django本身加载之前,在导入代码之前修补您的代码。根据您的入口点,您将找到正确的位置来修补您的代码。

使用Django 1.9,我可以考虑两个入口点:

  1. wsgi.py - 当您的代码在WSGI容器上运行时
  2. manage.py - 在运行任何管理命令(shell、runserver、migrate)时

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接