Обновление Monkey для Django в другом приложении

У нас есть сторонняя библиотека, которую мы используем в нашем приложении 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))

Ответ 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)

Ответ 2

Мне просто нужно было обезвредить адаптер django-allauth/django-invitation и наткнулся на те же ограничения (apps_ready == False).

Итак, я частично использовал то, что упомянули @domtes, отредактировав manage.py и вставив туда метод, чтобы частично переписать адаптер, который мне пришлось изменить, и, таким образом, добавив требуемое поведение. К моменту django загружен django-invitations, метод уже был перезаписан.

Это был простой, грязный и, возможно, не рекомендованный метод поиска и замены, в котором я переписал целевой файл .py, принадлежащий к структуре библиотеки.

Предположим, что он совместим с будущими версиями, но я признаю, что это источник ошибок и проблем.

Приветствия

Ответ 3

Monkey-patching - это взлом, который трудно поддерживать, и его следует избегать.

Принцип заключается в том, чтобы исправить ваш код до его импорта, прежде чем загружать Django. В зависимости от вашей точки входа вы найдете нужное место для исправления кода.

Используя Django 1.9, я могу думать о двух точках входа:

  • wsgi.py - пока ваш код запускается в контейнере WSGI
  • manage.py - при запуске любой команды управления (shell, runningerver, migrate)