python - tutorial - the django project
¿Cómo se recarga un módulo de modelo de Django utilizando el intérprete interactivo a través de "manage.py shell"? (9)
Bueno, creo que tengo que responder a esto. El problema es que Django almacena en caché sus modelos en un singleton (estructura similar a singleton) llamada AppCache. Básicamente, para volver a cargar los modelos Django, primero debe volver a cargar y volver a importar todos los módulos modelo almacenados en AppCache. Entonces debes eliminar la AppCache. Aquí está el código para ello:
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
Puse todo esto en un archivo separado llamado reloadmodels.py en el directorio raíz de mi sitio Django. Usando IPython puedo volver a cargar todo ejecutando:
%run ~/mysite/reloadmodels.py
Sé cómo volver a cargar un módulo de Python normal dentro de una sesión de intérprete de Python normal. Esta pregunta documenta cómo hacerlo bastante bien:
¿Cómo descargo (recargo) un módulo de Python?
Por algún motivo, tengo problemas para hacerlo en la sesión de intérprete "manage.py shell" de Django. Para recrear mi problema, inicie el tutorial básico de Django que se encuentra aquí:
Escribiendo tu primera aplicación Django, parte 1
Después de crear la aplicación "encuestas" y la clase "Encuesta", inicie el intérprete a través de "manage.py shell" e importe la aplicación "encuestas".
import polls.models as pm
Crea un nuevo objeto "Encuesta":
p = pm.Poll()
Todo está bien y bien hasta ahora. Ahora regrese a su fuente y agregue cualquier método o atributo arbitrario. Por ejemplo, he agregado:
def x(self):
return 2+2
Ahora regrese al intérprete y "vuelva a cargar" el módulo:
reload(pm)
Ahora intenta usar tu nuevo método o atributo:
p1 = pm.Poll()
p1.x()
Obtendrás este mensaje:
''Poll'' object has no attribute ''x''
¿Lo que da? También intenté volver a ejecutar el comando de importación, importando el módulo usando una sintaxis diferente, borrando todas las referencias a cualquier objeto "Encuesta" o a la clase "Encuesta". También he intentado esto con el intérprete de IPython y con el intérprete de Python (v2.6). Nada parece funcionar.
Usar las mismas técnicas con un módulo de Python arbitrario en una sesión de intérprete regular funciona perfectamente. Parece que no puedo hacer que funcione en la sesión de "shell" de Django.
Por cierto, si hace alguna diferencia, estoy haciendo esto en una máquina Ubuntu 9.04.
De las respuestas de Seti Volkylany y .com/a/5399339/3154274
- Instalar IPython:
pip install ipython
- Ejecute el
python manage.py shell
: el símbolo al comienzo de una línea debería estar ahoraIn [1]:
(en cmd era>>>
) - Ejecutar
ipython profile create
Vaya en
~/.ipython/profile_default/ipython_config.py
y ábralo en un editor de texto y agregue estas dos líneas al final:c.InteractiveShellApp.extensions = [''autoreload'']
c.InteractiveShellApp.exec_lines = [''% autoreload 2'']
Ahora puede ejecutar python manage.py shell
, edite sus modelos sin tener que escribir %autoreload 2
En lo que a mí respecta, ninguna de las soluciones anteriores funcionó por su cuenta, también this hilo no ayudó mucho por sí solo, pero después de combinar los enfoques logré volver a cargar mis modelos en shell_plus :
- Haga cambios en el modelo (MyModel)
- eliminar
models.pyc
Limpia la caché del modelo de Django (como here ):
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
Recargar el modelo como here
reload(project.app.models) from project.app.models import MyModel
Habilite la extensión de autorrecarga de IPython antes de importar cualquier código:
%load_ext autoreload
%autoreload 2
Lo uso con el shell regular de django y funciona perfectamente, aunque tiene algunas limitaciones:
* Advertencias:
Recargar los módulos de Python de manera confiable es en general difícil, y pueden ocurrir cosas inesperadas. El% de autorecarga intenta solucionar las trampas más comunes reemplazando los objetos del código de función y las partes de las clases anteriores en el módulo con nuevas versiones. Esto hace que las siguientes cosas funcionen:
- Las funciones y clases importadas a través de "desde xxx import foo" se actualizan a nuevas versiones cuando se vuelve a cargar "xxx".
- Los métodos y las propiedades de las clases se actualizan durante la recarga, de modo que llamar a ''c.foo ()'' en un objeto ''c'' creado antes de la recarga ocasiona que se ejecute el nuevo código para ''foo''.
Algunas de las advertencias restantes conocidas son:
- La sustitución de objetos de código no siempre tiene éxito: el cambio de una @property en una clase a un método ordinario o un método a una variable de miembro puede causar problemas (pero solo en objetos antiguos).
- Las funciones que se eliminan (por ejemplo, a través de parche de mono) desde un módulo antes de volver a cargarlas no se actualizan.
- Los módulos de extensión C no se pueden volver a cargar y, por lo tanto, no se pueden volver a cargar automáticamente. *
fuente: https://ipython.org/ipython-doc/3/config/extensions/autoreload.html#caveats
Otra gran opción es escribir su código en un script separado y enviarlo al shell django, así:
manage.py shell < my_script.py
No pude lograr que funcionase ninguna de las soluciones anteriores, pero se me ocurrió una solución alternativa para volver a cargar cualquier otro módulo que no sea de modelos en mi proyecto django (por ejemplo, un módulo functions.py
o views.py
).
Crea un archivo llamado
reimport_module.py
. Lo almacené en la carpetalocal/
de mi proyecto django en mi máquina de desarrollo.# 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)
Lanzar shell plus (que usa un shell IPython incrustado):
python manage.py shell_plus
Use lo siguiente para importar el módulo que está desarrollando:
%run local/reimport_module.py ''your.module''
Use IPython para probar funciones en su módulo.
- Realice cambios en el módulo en un editor externo.
Utilice lo siguiente para volver a importar el módulo sin tener que salir y volver a ingresar a IPython:
%run local/reimport_module.py ''your.module''
Nota: este comando ya se utilizó en el paso 3, por lo que puede escribir
%run
luego la flecha hacia arriba para autocompletarlo.
Suponiendo que su proyecto está configurado de esta manera
- nombre del proyecto: librería
- nombre de la aplicación: estante
- nombre del modelo: Libros
primera carga
from bookstore.shelf.models import Books
recargas posteriores
import bookstore;reload(bookstore.shelf.models);from bookstore.shelf.models import Books
También puede usar el proyecto django-extensions con el siguiente comando:
manage.py shell_plus --notebook
Esto abrirá un cuaderno IPython en su navegador web en lugar del intérprete de shell IPython. Escriba su código allí y ejecútelo.
Cuando cambie sus módulos, simplemente haga clic en la opción del menú de la página web ''Kernel-> Restart''
Volver a ejecutar el código ahora usa tus módulos modificados.
la consola ipython realiza una recarga profunda con cada expresión reload()
; y por supuesto agrega muchas otras cosas útiles.
Mi solución en 2016 (en el futuro se puede cambiar)
1. Instalar django_extension
2. Añadir la siguiente configuración:
SHELL_PLUS = ''ipython''
IPYTHON_ARGUMENTS = [
''--ext'', ''autoreload'',
]
3.Run shell
./manage.py shell_plus
Ver resultados:
ejemplo modelo
class Notification(models.Model):
........
@classmethod
def get_something(self):
return ''I am programmer''
Concha
In [1]: Notification.get_something()
Out[1]: ''I am programmer''
Cambios hechos en el modelo
@classmethod
def get_something(self):
return ''I am Python programmer''
Concha
# shell does not display changes
In [2]: Notification.get_something()
Out[2]: ''I am programmer''
Concha. Esto es una magia
# configure extension of ipython
In [3]: %autoreload 2
Concha
# try again - all worked
In [4]: Notification.get_something()
Out[4]: ''I am Python programmer''
Hecho cambios otra vez
@classmethod
def get_something(self):
return ''I am full-stack Python programmer''
Concha
# all worked again
In [5]: Notification.get_something()
Out[5]: ''I am full-stack Python programmer''
Drawback: 1. Necesita código de ejecución manual
% autorecarga 2
ya que django_extension 1.7 no tiene soporte para ejecutar código arbitrario. Puede estar en una versión futura tiene esta característica.
Notas:
- Django 1.10
- Python 3.4
- django_extension 1.7.4
- Basado (primario) en https://django-extensions.readthedocs.io/en/latest/shell_plus.html y http://ipython.readthedocs.io/en/stable/config/extensions/autoreload.html
- Precaución. Se puede producir un error, si intenta cambiar un código donde se usa super ().