¿Cómo tener un script de Python para una aplicación de Django que acceda a modelos sin usar el shell manage.py?

6 minutos de lectura

Avatar de usuario de Trindaz
Trindaz

Estoy escribiendo un script para importar algunos objetos modelo a la base de datos que usa mi aplicación django. En el pasado, he resuelto esto ejecutando ./manage.py shell y entonces import myscript. Estoy seguro de que hay una mejor manera. Me gustaría poder llamar a un script desde cualquier lugar de mi HD usando python scriptname.pyy en las primeras líneas de ese script haría cualquier importación/otra operación necesaria para poder acceder a los objetos del modelo y comportarse como si se ejecutara usando manage.py shell.

¿Qué necesito agregar a mi script para lograr esto?

EDITAR:

Basado en la respuesta de @Melug, con la adición de la configuración dinámica de la ruta de Python para abordar la parte de la pregunta “en cualquier lugar de mi HD”:

import sys
sys.path.append('c:\\my_projec_src_folder')
from myproject import settings
from django.core.management import setup_environ
setup_environ(settings)

  • Las respuestas a esta pregunta son una pistola de pie. La mayoría de las personas querrán usar manage.py porque esta pregunta aparece ampliamente en las búsquedas y no es necesario invocar shell para usar manage.py. La mayoría de las personas que vienen aquí querrán esta respuesta: stackoverflow.com/a/8047520/108512

    – Andrés Johnson

    27 oct 2021 a las 16:16


Avatar de usuario de Michael
Miguel

Desde Django 1.4 debes evitar usar setup_environ(settings) (publicación de Melug) porque está en desuso. Utilice lo siguiente en su lugar y podrá acceder a su modelo

import os

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "your_project_name.settings")

# your imports, e.g. Django models
from your_project_name.models import Location

# From now onwards start your script..

Aquí hay un ejemplo para acceder y modificar su modelo:

if __name__ == '__main__':    
    # e.g. add a new location
    l = Location()
    l.name="Berlin"
    l.save()

    # this is an example to access your model
    locations = Location.objects.all()
    print locations

    # e.g. delete the location
    berlin = Location.objects.filter(name="Berlin")
    print berlin
    berlin.delete()

Modelo de ejemplo:

class Location(models.Model):
    name = models.CharField(max_length=100)

  • Esto funcionó para mí solo después de que moví os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, “your_project_name.settings”) a la línea inmediatamente después de import os. De lo contrario, esta es una solución mucho mejor.

    – Pedro H.

    29 de septiembre de 2013 a las 5:27

  • ¡Buen punto, Pedro! Tal vez algunas importaciones de modelos solo funcionen después de la os.environ.setdefault(...) línea. Reorganicé las importaciones en mi publicación, ahora debería funcionar para todos. PD: Si le gusta aún más esta solución, vote por ella. ¡Gracias!

    – Miguel

    29/09/2013 a las 17:50


  • ¿Puedo hacer esto sin un archivo de configuración externo? Es decir, quiero construir los modelos, la conexión y todo en un solo script. No me importan las vistas…

    – isaaclw

    11 de enero de 2016 a las 3:34


  • @isaaclw No creo que puedas hacer esto sin un archivo de configuración. Si encuentra una manera, por favor háganoslo saber. Por cierto. mi settings.py lo hace no maneja cualquier vista, maneja los parámetros de conexión, indicadores como el modo de depuración, etc. Todas las vistas se definen dentro del myapp/views.py y se puede acceder mediante patrones de URL definidos en urls.py

    – Miguel

    11 de enero de 2016 a las 13:39


  • Casi lo tenía, solo necesitaba configurar el archivo de configuración en algo. Actualmente lo tengo configurado en una cadena vacía. DATABASES = {} está configurado correctamente. Después: os.environ["DJANGO_SETTINGS_MODULE"] = '' y settings.configure(**locals()) Todo eso viene antes from django.db import models

    – isaaclw

    11/01/2016 a las 20:38


Avatar de usuario de Rebs
rebeldes

Para cargar los modelos también, tuve que combinar esto con esta respuesta, de lo contrario obtengo django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet

import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "my_project.settings")
import django
django.setup()

Como extra, añado esto a la __init__.py de mis proyectos django, descubrirá automáticamente el nombre de la aplicación para que pueda copiar/pegar:

import os


def setup():
    module = os.path.split(os.path.dirname(__file__))[-1]
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{}.settings".format(module))
    import django
    django.setup()

Entonces solo puedo hacer:

from <app> import setup
setup()

  • Gracias, aparentemente es necesario llamar a setup() ya que Django 1.7.

    – Phae7rae

    22 de enero de 2015 a las 16:01

  • La configuración () en init es agradable, ¡me encanta!

    – ulat

    19 de septiembre de 2016 a las 9:01

  • Esta debería ser la respuesta correcta ahora. Única solución que funciona para mí.

    – AlfazOeste

    22 de diciembre de 2017 a las 18:01

  • He notado 2 cosas: 1) se producen errores cuando hay configuraciones en varios archivos, 2) setup () no funciona cuando se llama en models.py, de lo contrario, es una gran respuesta

    – yvesva

    8 de marzo de 2018 a las 23:06

  • @yvesva No debería llamar a esto desde su models.py. Esto es para inicializar django desde scripts externos. No use esto dentro de su flujo de llamadas estándar de la aplicación django. ¿Y no debería haber ningún problema con poner esto en varios archivos? Siempre que la ruta del módulo que obtiene la función sea apropiada, funcionará. Tengo la impresión de que no lo estás haciendo correctamente.

    – Rebeldes

    3 abr 2018 a las 10:40

Avatar de usuario de Alkindus
Alkindus

Para Django versión 1.9 o posterior, puede usar esto:

import sys
import os
import django

sys.path.append('your_project_directory')
os.environ['DJANGO_SETTINGS_MODULE'] = 'your_project.settings'
django.setup()

from yourapp.models import your_model

para que pueda usar el objeto como el mismo objeto django:

from myapp.models import Locations
all_locations = Locations.object.all()
first_location = Locations.object.get(id=1)
print first_location.name()
first_location.save()

  • ¡Esto funcionó para mí! Django 2.0. ¿Por qué exactamente necesitamos agregar la ruta con nuestro directorio de proyectos? ¿Hay alguna buena información sobre lo que django.setup() hace en alto nivel?

    – timbre

    16 oct 2018 a las 14:00

  • @timbram – ¿te has enterado? ¿Hay alguna forma de automatizar esto en editores de texto como sublime text 3 o atom?

    – cobertura cero

    16 abr 2019 a las 17:20

  • Esta es la única solución que funciona con la última versión LTS (3.2) en Windows.

    – Prahlada Yeri

    20 de abril de 2021 a las 3:47

Creo que la mejor manera es crear tu comando(s) de administración personalizado(s). Entonces puedes llamar manage.py <yourcommand> de donde sea.

Primero debe configurar el entorno Django:

from your_project import settings
from django.core.management import setup_environ
setup_environ(settings)

Por fin importe sus modelos, todo va como Django.

  • setup_environ(settings) está en desuso desde Django 1.4! Mi publicación a continuación muestra una alternativa que incluye un ejemplo.

    – Miguel

    12 de septiembre de 2013 a las 10:13

Avatar de usuario de la comunidad
Comunidad

Para DJANGO 1,11

Las soluciones superiores no funcionaron, pero me dieron un error:

django.core.exceptions.AppRegistryNotReady: las aplicaciones aún no están cargadas.

Para mí, la solución de aquí funcionó:

import os
from django.core.wsgi import get_wsgi_application

os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'
application = get_wsgi_application()

  • setup_environ(settings) está en desuso desde Django 1.4! Mi publicación a continuación muestra una alternativa que incluye un ejemplo.

    – Miguel

    12 de septiembre de 2013 a las 10:13

avatar de usuario de jdm
jdm

Desde al menos Django 1.11, su aplicación principal incluye un módulo wsgi que realiza la configuración necesaria en la importación. Asumiendo myproject/myproject es donde está tu settings.py, en tu script solo importa:

from myproject.wsgi import application

¿Ha sido útil esta solución?