Подтвердить что ты не робот

Как перезагрузить модуль модели 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.
4b9b3361

Ответ 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. Напишите свой код и запустите его.

Когда вы меняете свои модули, просто нажмите на пункт меню "Ядро- > Перезагрузка"

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

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