Как перезагрузить модуль модели Django с помощью интерактивного интерпретатора через "manage.py shell"? - PullRequest
53 голосов
/ 21 мая 2009

Я знаю, как перезагрузить обычный модуль Python в рамках обычной сессии интерпретатора Python. Этот вопрос описывает, как это сделать довольно хорошо:

Как выгрузить (перезагрузить) модуль Python?

По какой-то причине у меня возникают проблемы с этим в сеансе интерпретатора Django "manage.py shell". Чтобы воссоздать мою проблему, запустите базовое руководство по Django, найденное здесь:

Написание вашего первого приложения Django, часть 1

После создания приложения "polls" и класса "Poll" запустите интерпретатор через "manage.py shell" и импортируйте в него приложение "polls".

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 в обычной сессии интерпретатора работает отлично. Я просто не могу заставить его работать в сеансе «оболочки» Джанго.

Кстати, если это что-то меняет, я делаю это на машине с Ubuntu 9.04.

Ответы [ 9 ]

38 голосов
/ 24 мая 2009

Ну, я думаю, что должен ответить на это. Проблема в том, что Django кэширует свои модели в одноэлементной (одноэлементной структуре), называемой 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
6 голосов
/ 11 декабря 2013

Вы также можете использовать проект django-extensions с помощью следующей команды:

manage.py shell_plus --notebook

Это откроет записную книжку IPython в вашем веб-браузере вместо интерпретатора оболочки IPython. Напишите свой код и запустите его.

Когда вы меняете свои модули, просто нажмите на пункт меню веб-страницы 'Kernel-> Restart'

Повторный запуск кода теперь использует ваши измененные модули.

5 голосов
/ 16 ноября 2016

Мое решение на 2016 год (в будущем оно может быть изменено)

1.Установите django_extension

2.Добавить следующие настройки:

SHELL_PLUS = 'ipython'

IPYTHON_ARGUMENTS = [
    '--ext', 'autoreload',
]

3.Run shell

./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. Нужно вручную запустить код

% автозагрузка 2

, поскольку django_extension 1.7 не поддерживает запуск произвольного кода. Может быть, в будущем выпуске у него есть эта функция.

Примечания:

  1. Джанго 1.10
  2. Python 3.4
  3. django_extension 1.7.4
  4. На основе (основной) на https://django -extensions.readthedocs.io / en / latest / shell_plus.html и http://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html
  5. Внимание. Это может привести к ошибке, если вы попытаетесь изменить код, где используется super ().
5 голосов
/ 12 августа 2010

Насколько мне известно, ни одно из вышеперечисленных решений не работало само по себе, также этот поток не сильно помог сам по себе, но после объединения подходов мне удалось перезагрузить модели в shell_plus :

  1. Внести изменения в модель (MyModel)
  2. удалить models.pyc
  3. Очистить кеш модели 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
    
  4. Перезагрузить модель как здесь

    reload(project.app.models)
    from project.app.models import MyModel
    
5 голосов
/ 16 октября 2009

Если ваш проект настроен таким образом

  • название проекта: книжный магазин
  • название приложения: полка
  • название модели: Books

первая загрузка

from bookstore.shelf.models import Books

последующие перезагрузки

import bookstore;reload(bookstore.shelf.models);from bookstore.shelf.models import Books
3 голосов
/ 21 мая 2009

консоль ipython выполняет глубокую перезагрузку с каждым reload() выражением; и, конечно, добавляет много других полезных вещей.

2 голосов
/ 01 октября 2017

Из ответов Сети Волкиляны и pv

  1. Установить IPython: pip install ipython
  2. Выполнить python manage.py shell: символ в начале строки теперь должен быть In [1]: (в cmd это было >>>)
  3. Выполнить ipython profile create
  4. Зайдите в ~/.ipython/profile_default/ipython_config.py и откройте его в текстовом редакторе и добавьте две строки в конце:

    c.InteractiveShellApp.extensions = ['autoreload']
    c.InteractiveShellApp.exec_lines = ['% autoreload 2']

Теперь вы можете запустить python manage.py shell, редактировать свои модели без необходимости писать %autoreload 2

1 голос
/ 07 октября 2016

Включить расширение автозагрузки IPython перед импортом любого кода:

%load_ext autoreload
%autoreload 2

Я использую его с обычной оболочкой django, и она отлично работает, хотя и имеет некоторые ограничения:

* Предостережения:

Перезагружать модули Python надежным способом, как правило, сложно, и могут произойти непредвиденные ситуации. % autoreload пытается обойти распространенные ловушки, заменяя объекты кода функций и части классов, ранее находившиеся в модуле, новыми версиями. Это заставляет работать следующие вещи:

  • Функции и классы, импортированные с помощью «из xxx import foo», обновляются до новых версий при перезагрузке «xxx».
  • Методы и свойства классов обновляются при перезагрузке, поэтому вызов ccoo () для объекта «c», созданного до перезагрузки, приводит к выполнению нового кода для «foo».

Некоторые из известных оставшихся предостережений:

  • Замена объектов кода не всегда успешна: изменение @property в классе на обычный метод или метод на переменную-член может вызвать проблемы (но только для старых объектов).
  • Функции, которые были удалены (например, с помощью мартышки) из модуля до его перезагрузки, не обновляются.
  • Модули расширения C не могут быть перезагружены, и поэтому не могут быть автоматически перезагружены. *

источник: https://ipython.org/ipython-doc/3/config/extensions/autoreload.html#caveats

Еще один отличный вариант - написать свой код в отдельном скрипте и отправить его в оболочку django, например:

manage.py shell < my_script.py
0 голосов
/ 15 июля 2012

Мне не удалось заставить работать ни одно из перечисленных выше решений, но я нашел обходной путь для перезагрузки любого другого модуля, не являющегося моделью, в моем проекте django (например, модуль functions.py или views.py) .

  1. Создайте файл с именем reimport_module.py. Я сохранил его в папке local/ моего проекта django на моем компьютере разработчика.

    # 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) 
    
  2. Запустить shell plus (который использует встроенную оболочку IPython):

    python manage.py shell_plus

  3. Используйте следующее для импорта разрабатываемого вами модуля:

    %run local/reimport_module.py 'your.module'

  4. Используйте IPython для тестирования функций в вашем модуле.

  5. Внести изменения в модуль во внешнем редакторе.
  6. Используйте следующее для повторного импорта модуля без необходимости выхода и повторного входа в IPython:

    %run local/reimport_module.py 'your.module'

    Примечание: эта команда уже использовалась на шаге 3, поэтому вы можете набрать %run и стрелку вверх для ее автозаполнения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...