Как перезагрузить модуль модели Django с помощью интерактивного интерпретатора через "manage.py shell"?
Я знаю, как перезагрузить обычный модуль Python в рамках обычного сеанса интерпретатора Python. Этот вопрос документирует, как это сделать довольно хорошо:
Как выгрузить (перезагрузить) модуль Python?
По какой-то причине у меня возникают проблемы с этим в сеансе интерпретатора Django "manage.py shell". Чтобы воссоздать мою проблему, запустите базовый учебник Django, который можно найти здесь:
Написание первого приложения Django, часть 1
После создания приложения "опросы" и класса "Опрос" запустите интерпретатор через "manage.py shell" и импортируйте приложение "опросы" в него.
import polls.models as pm
Создайте новый объект "Опрос":
p = pm.Poll()
Все хорошо и хорошо. Теперь вернитесь к своему источнику и добавьте произвольный метод или атрибут. Например, я добавил:
def x(self):
return 2+2
Теперь вернитесь к интерпретатору и "перезагрузите" модуль:
reload(pm)
Теперь попробуйте использовать новый метод или атрибут:
p1 = pm.Poll()
p1.x()
Вы получите следующее сообщение:
'Poll' object has no attribute 'x'
Что дает? Я также попытался перезапустить команду импорта, импортировав модуль с использованием другого синтаксиса, удалив все ссылки на любые объекты "Опрос" или "Опрос". Я также пробовал это как с интерпретатором IPython, так и с простым интерпретатором Python (v2.6). Кажется, что ничего не работает.
Использование тех же методов с произвольным модулем Python в регулярном сеансе интерпретатора отлично работает. Я просто не могу заставить его работать в сеансе Django "shell".
Кстати, если это имеет значение, я делаю это на машине Ubuntu 9.04.
Ответы
Ответ 1
Ну, я думаю, я должен ответить на это. Проблема в том, что Django кэширует свои модели в одноэлементном (singleton like structure), называемом AppCache. В принципе, для перезагрузки моделей Django вам необходимо сначала перезагрузить и повторно импортировать все модули модели, хранящиеся в AppCache. Затем вам нужно уничтожить AppCache. Вот код для него:
import os
from django.db.models.loading import AppCache
cache = AppCache()
curdir = os.getcwd()
for app in cache.get_apps():
f = app.__file__
if f.startswith(curdir) and f.endswith('.pyc'):
os.remove(f)
__import__(app.__name__)
reload(app)
from django.utils.datastructures import SortedDict
cache.app_store = SortedDict()
cache.app_models = SortedDict()
cache.app_errors = {}
cache.handled = {}
cache.loaded = False
Я поместил все это в отдельный файл с именем reloadmodels.py в корневой каталог моего сайта Django. Используя IPython, я могу перезагрузить все, выполнив:
%run ~/mysite/reloadmodels.py
Ответ 2
Предполагая, что ваш проект настроен таким образом
- название проекта: книжный магазин
- имя приложения: полка
- название модели: книги
первая загрузка
from bookstore.shelf.models import Books
последующие перезагрузки
import bookstore;reload(bookstore.shelf.models);from bookstore.shelf.models import Books
Ответ 3
Насколько я понимаю, ни один из вышеперечисленных решений не работал сам по себе, также этот нить не помог сам по себе, но после объединения подходы, которые мне удалось перезагрузить мои модели в shell_plus:
- Внести изменения в модель (MyModel)
- удалить
models.pyc
-
Очистите кеш модели Django (например здесь):
from django.db.models.loading import AppCache
cache = AppCache()
from django.utils.datastructures import SortedDict
cache.app_store = SortedDict()
cache.app_models = SortedDict()
cache.app_errors = {}
cache.handled = {}
cache.loaded = False
-
Перезагрузить модель, например здесь
reload(project.app.models)
from project.app.models import MyModel
Ответ 4
Вы также можете использовать проект django-extensions со следующей командой:
manage.py shell_plus --notebook
Это откроет ноутбук IPython в вашем веб-браузере вместо интерпретатора оболочки IPython. Напишите свой код и запустите его.
Когда вы меняете свои модули, просто нажмите на пункт меню "Ядро- > Перезагрузка"
Повторный запуск кода теперь использует измененные модули.
Ответ 5
консоль ipython делает глубокую перезагрузку с помощью каждое выражение reload()
; и, конечно, добавляет много других полезных вещей.
Ответ 6
Мое решение в 2016 году (в будущем оно может быть изменено)
1.Установить django_extension
2. Добавьте следующие настройки:
SHELL_PLUS = 'ipython'
IPYTHON_ARGUMENTS = [
'--ext', 'autoreload',
]
оболочка 3.Run
./manage.py shell_plus
См. результаты:
пример модели
class Notification(models.Model):
........
@classmethod
def get_something(self):
return 'I am programmer'
В оболочке
In [1]: Notification.get_something()
Out[1]: 'I am programmer'
Сделаны изменения на модели
@classmethod
def get_something(self):
return 'I am Python programmer'
В оболочке
# shell does not display changes
In [2]: Notification.get_something()
Out[2]: 'I am programmer'
В оболочке. Это волшебство
# configure extension of ipython
In [3]: %autoreload 2
В оболочке
# try again - all worked
In [4]: Notification.get_something()
Out[4]: 'I am Python programmer'
Сделаны изменения снова
@classmethod
def get_something(self):
return 'I am full-stack Python programmer'
В оболочке
# all worked again
In [5]: Notification.get_something()
Out[5]: 'I am full-stack Python programmer'
Минус:
1. Нужно вручную запустить код
% autoreload 2
поскольку django_extension 1.7 не поддерживает запуск произвольного кода. Возможно, в будущем выпуске будет эта функция.
Примечания:
Ответ 7
Включить расширение автозагрузки IPython перед импортом любого кода:
%load_ext autoreload
%autoreload 2
Я использую его с обычной оболочкой django, и он отлично работает, хотя у него есть некоторые ограничения:
* Предостережения:
Перезагрузка модулей Python надежным способом в целом сложна, и могут возникнуть непредвиденные ситуации. % autoreload пытается обойти общие ошибки, заменив объекты функционального кода и части классов ранее в модуле новыми версиями. Это делает следующие действия:
- Функции и классы, импортированные с помощью 'from xxx import foo, обновляются до новых версий, когда xxx перезагружается.
- Методы и свойства классов обновляются при перезагрузке, так что вызов c.foo() для объекта c, созданного до перезагрузки, вызывает выполнение нового кода для 'foo.
Некоторые из известных оставшихся оговорок:
- Замена объектов кода не всегда выполняется: изменение класса @property в классе на обычный метод или метод на переменную-член может вызвать проблемы (но только в старых объектах).
- Функции, которые удаляются (например, с помощью исправления обезьяны) из модуля до его перезагрузки, не обновляются.
- Модули расширения C не могут быть перезагружены и поэтому не могут быть загружены автозагрузкой. *
источник: https://ipython.org/ipython-doc/3/config/extensions/autoreload.html#caveats
Еще один замечательный вариант - написать свой код в отдельном script и отправить его в оболочку django, например:
manage.py shell < my_script.py
Ответ 8
Мне не удалось заставить любое из вышеперечисленных решений работать, но я придумал обходной способ для перезагрузки любого другого модуля немодулей в моем проекте django (например, модуль functions.py
или views.py
).
-
Создайте файл с именем reimport_module.py
. Я сохранил его в папке local/
моего проекта django на моей машине dev.
# Desc: Imports the module with the name passed in, or imports it for first
# time if it hasn't already been imported.
#
# Purpose of this script is to speed up development of functions that
# are written in an external editor then tested in IPython.
#
# Without this script you have to exit & reenter IPython then redo
# import statements, definitions of local variables, etc.
#
# Note: doesn't work for Django models files, because Django caches
# them in a structure called AppCache.
#
# Args: module to reload (string)
import sys
module_to_reload = sys.argv[1]
# Attempt to pop module
try:
sys.modules.pop(module_to_reload)
print 'reimporting...'
except KeyError:
print 'importing for first time...'
# (re)import module
import_str = 'from {0} import *'.format(module_to_reload)
exec(import_str)
-
Запустите shell plus (который использует встроенную оболочку IPython):
python manage.py shell_plus
-
Для импорта модуля, который вы разрабатываете, используйте следующее:
%run local/reimport_module.py 'your.module'
-
Используйте IPython для тестирования функций в вашем модуле.
- Внесите изменения в модуль во внешнем редакторе.
-
Используйте следующий модуль reimport, без необходимости его выхода и повторного входа в IPython:
%run local/reimport_module.py 'your.module'
Примечание: эта команда уже использовалась на шаге 3, поэтому вы можете ввести %run
, затем стрелку вверх, чтобы автозавершить ее.
Ответ 9
Из ответов Seti Volkylany и pv
- Установить IPython:
pip install ipython
- Выполнить
python manage.py shell
: теперь символ в начале строки должен быть In [1]:
(в cmd он был >>>
)
- Запустить
ipython profile create
-
Перейдите в ~/.ipython/profile_default/ipython_config.py
и откройте его в текстовом редакторе и добавьте эти две строки в конец:
c.InteractiveShellApp.extensions = ['autoreload']
c.InteractiveShellApp.exec_lines = ['% autoreload 2']
Теперь вы можете запустить python manage.py shell
, отредактировать свои модели, не записывая %autoreload 2