Обновление 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)