88

I'm writing a script to import some model objects into the database my django application uses. In the past I've solved this by running ./manage.py shell and then import myscript. I'm sure there's a better way. I'd like to be able to call a script from anywhere on my HD using python scriptname.py, and in the first few lines of that script it would do whatever imports / other operations necessary so that it can access model objects and behave as though it was run using manage.py shell.

What do I need to add to my script to achieve this?

EDIT:

Based on @Melug's answer, with addition of dynamically setting Python path to address the 'anywhere on my HD' part of the question:

import sys
sys.path.append('c:\\my_projec_src_folder')
from myproject import settings
from django.core.management import setup_environ
setup_environ(settings)
Dave Mackey
  • 4,306
  • 21
  • 78
  • 136
Trindaz
  • 17,029
  • 21
  • 82
  • 111
  • The answers to this question are a foot gun. Most people will want to use manage.py because this question turns up broadly for searches, and you don't need to invoke shell to use manage.py. Most people who come here will want this answer: https://stackoverflow.com/a/8047520/108512 – Andrew Johnson Oct 27 '21 at 16:16

13 Answers13

156

Since Django 1.4 you should avoid using setup_environ(settings) (post by Melug) because it is deprecated. Use the following instead and you will be able to access your model

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..

Here is an example to access and modify your model:

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()

Example model:

class Location(models.Model):
    name = models.CharField(max_length=100)
Michael
  • 3,982
  • 4
  • 30
  • 46
  • 4
    This worked for me only after I moved os.environ.setdefault("DJANGO_SETTINGS_MODULE", "your_project_name.settings") to the line immediately after import os. Otherwise, this is a much better solution. – Peter H Sep 29 '13 at 05:27
  • Good point, Peter! Maybe some model imports just work after the `os.environ.setdefault(...)` line. I rearranged the imports in my post, now it should work for everyone. PS: If you like this solution even better, please vote for it. Thanks! – Michael Sep 29 '13 at 17:50
  • Can I do this without an external settings file? That is to say I want to build the models, the connection, and everything in side a single script. I don't care about views... – isaaclw Jan 11 '16 at 03:34
  • @isaaclw I don't believe you can do this without a settings file. If you find a way, please let us know. Btw. my `settings.py` does _not_ handle any views, it handles connection parameters, flags like debug mode, etc. All views are defined inside the `myapp/views.py` and can be accessed by url patterns defined in `urls.py` – Michael Jan 11 '16 at 13:39
  • I almost had it, I just needed to set the settings file to something. Currently I have it set to empty string. DATABASES = {} is set appropriately. Then: `os.environ["DJANGO_SETTINGS_MODULE"] = ''` and `settings.configure(**locals())` That all comes before `from django.db import models` – isaaclw Jan 11 '16 at 20:38
  • Where in the file directory does this file go? – User Sep 25 '19 at 00:54
  • @Michael, are you happen to know if this solution cares about DB connection pool settings (e.g. CONN_MAX_AGE)? Just going to use it with long-living process (socket.io server to be more specific) and wondering if it suitable for my case. Thanks. – zoryamba Sep 02 '21 at 18:32
139

To get models loaded too, I had to combine this with this answer, otherwise I get django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet

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

As an extra, I add this to the __init__.py of my django projects, it will automatically discover the app name so it is copy/paste-able:

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()

Then I can just do:

from <app> import setup
setup()
Community
  • 1
  • 1
Rebs
  • 4,169
  • 2
  • 30
  • 34
  • 10
    Thanks, apparently it is required to call setup() since **Django 1.7**. – Phae7rae Jan 22 '15 at 16:01
  • 1
    The setup() in init is nice, love it! – ulath Sep 19 '16 at 09:01
  • 1
    This should be the correct answer now. Only solution that works for me. – alphazwest Dec 22 '17 at 18:01
  • I've noticed 2 things: 1) errors are thrown when there are setups in multiple files, 2) setup() doesn't work when called in models.py, otherwise great answer – yvesva Mar 08 '18 at 23:06
  • 1
    @yvesva You shouldn't be calling this from your models.py. This is for initialising django from external scripts. Don't use this within your standard django app call flow. And there shouldn't be any problem with putting this in multiple files? As long as the module path the function gets is appropriate it will work. I'm getting the impression you're not doing this correctly. – Rebs Apr 03 '18 at 10:40
  • setup() in __init__ is neat! Thanks @rebs – Alen Jacob Apr 02 '20 at 01:41
48

For Django version 1.9 or later you can use this:

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

so you can use object as same django object:

from myapp.models import Locations
all_locations = Locations.object.all()
first_location = Locations.object.get(id=1)
print first_location.name()
first_location.save()
Alkindus
  • 2,064
  • 2
  • 16
  • 16
  • 3
    This worked for me! Django 2.0. Why exactly do we need to append the path with our project directory? Is there any good info on what django.setup() does high level? – timbram Oct 16 '18 at 14:00
  • @timbram - have you found out? is there a way to automate this in text editors like sublime text 3 or atom? – zerohedge Apr 16 '19 at 17:20
  • This is the only solution that works with the latest LTS version (3.2) on Windows. – Prahlad Yeri Apr 20 '21 at 03:47
41

I think the best way is to create your custom management command(s). Then you can call manage.py <yourcommand> from anywhere.

DrTyrsa
  • 31,014
  • 7
  • 86
  • 86
24

You need to setup django environment first:

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

At last import your models, everything goes just like django.

Melug
  • 1,023
  • 9
  • 14
  • 30
    `setup_environ(settings)` is deprecated since Django 1.4! My post below shows an alternative including an example. – Michael Sep 12 '13 at 10:13
11

FOR DJANGO 1.11

Upper solutions did not work, but gave me an error:

django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

For me solution from here worked out:

import os
from django.core.wsgi import get_wsgi_application

os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'
application = get_wsgi_application()
Community
  • 1
  • 1
Henhuy
  • 1,034
  • 1
  • 13
  • 23
4

Since at least Django 1.11, your main app includes a wsgi module that does the neccessary setup on import. Assuming myproject/myproject is where your settings.py is, in your script just import:

from myproject.wsgi import application
jdm
  • 9,470
  • 12
  • 58
  • 110
2

Here is the answer for Django versions > 1.4:

from django.core.management import settings
from myproject.myproject import settings as project_settings

if not settings.configured:
  settings.configure(default_settings=project_settings)
ISP
  • 21
  • 3
2

If you get:

django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.

Try:

import os
from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myapp.settings')
application = get_wsgi_application()
juan Isaza
  • 3,646
  • 3
  • 31
  • 37
  • 2
    I am using a standalone script in Django which is importing the Models. I tried the above technique and I am getting the following error RuntimeError: populate() isn't reentrant – AR7 Jul 04 '18 at 12:41
  • @AR7 did you found a way around this error? I'm running into the same problem. – Justcurious Oct 20 '19 at 15:28
  • I think the reentrat error happens when you are calling the get_wsgi_application() more than once. – juan Isaza Dec 11 '19 at 02:03
2

for django >= 2.0 it is enough to do these 2 imports

from your_project_path import settings as your_project_settings
from django.core.management import settings

then you can do just from my_app.models import MyModel

and work with your Model MyModel

Martin Nowosad
  • 791
  • 8
  • 15
1

Try:

os.environ["DJANGO_SETTINGS_MODULE"] = "mysite.settings"

if os.environ.setdefault doesn't work. (Windows 10, python3.6.4, django 2.0.3)

yvesva
  • 711
  • 7
  • 10
0

As Stavros pointed out here, you can just copy the wsgi.py and put it at the beginning of you script. Besides setting up DJANGO_SETTINGS_MODULE, you also need to get the applications. Hope it helps. It works for me at django 2.1.5.

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'revochem.settings')

application = get_wsgi_application()
user1422543
  • 81
  • 1
  • 4
0

Many of the above answers are correct, but don't reference the official documentation.

First you need to configure settings or set the DJANGO_SETTINGS_MODULE envrionment variable

from django.conf import settings
if not settings.configured:
    settings.configure(myapp_defaults, DEBUG=True)

The docs then specify:

After you’ve either set DJANGO_SETTINGS_MODULE or called configure() you’ll need to call django.setup() to load your settings and populate Django’s application registry. For example:

import django from django.conf
import settings from myapp
import myapp_defaults

settings.configure(default_settings=myapp_defaults, DEBUG=True)
django.setup()

# Now this script or any imported module can use any part of Django it needs. from myapp import models ```

The docs also include an important caveat:

django.setup() may only be called once.

Therefore, avoid putting reusable application logic in standalone scripts so that you have to import from the script elsewhere in your application. If you can’t avoid that, put the call to django.setup() inside an if block:

if __name__ == '__main__':
    import django
    django.setup()
leafmeal
  • 1,824
  • 15
  • 15