35

I am trying to access my Django (v1.10) app DB from another python script and having some trouble doing so.

This is my file and folder structure:

store
 store
   __init.py__
   settings.py
   urls.py
   wsgi.py
 store_app
   __init.py__
   admin.py
   apps.py
   models.py
   ...
 db.sqlite3
 manage.py

other_script.py

In accordance with Django's documentations my other_script.py looks like this:

import django
from django.conf import settings

settings.configure(DEBUG=True)
django.setup()

from store.store_app.models import MyModel

But it generates a runtime error:

RunTimeError: Model class store.store_app.models.MyModel doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

I should note that my INSTALLED_APPS list contains store_app as its last element.

If instead I try to pass a config like this:

import django
from django.conf import settings
from store.store_app.apps import StoreAppConfig

settings.configure(StoreAppConfig, DEBUG=True)
django.setup()

from store.store_app.models import MyModel

I get:

AttributeError: type object 'StoreAppConfig has no attribute  'LOGGING_CONFIG'.

If I edit settings.py and add LOGGING_CONFIG=None I get another error about another missing attribute, and so on.

Any suggestions will be appreciated.

Alex
  • 5,759
  • 1
  • 32
  • 47
Ben RR
  • 913
  • 2
  • 10
  • 15

6 Answers6

59

Try this

import sys, os, django
sys.path.append("/path/to/store") #here store is root folder(means parent).
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "store.settings")
django.setup()

from store_app.models import MyModel

This script you can use anywhere in your system.

itzMEonTV
  • 19,851
  • 4
  • 39
  • 49
  • 1
    Great! Note I needed to use `"store.store.settings"` for it to work. – Ben RR Sep 27 '16 at 12:13
  • 2
    If file is nearby manage.py, path to append sys.path.append(os.path.dirname(os.path.abspath(__file__))) – Igor Mar 14 '18 at 08:06
  • I had `django.urls.reverse()` call in my script, and one of my `urls.py`'s had `reverse()` calls as well. Thus, my `reverse()` call led to loading `urls.py`'s, which in effect made another "recursive" call to `reverse()`. That triggered [`NoReverseMatch`](https://stackoverflow.com/questions/39917987/django-1-9-to-1-10-raises-noreversematch-uen-gb-is-not-a-registered-namespace) exception. I dealt with it by doing `from django.core import checks; checks.run_checks()` before doing reverse match. Although there might be a better way. – x-yuri Sep 06 '18 at 18:10
  • `sys.path.append` is supposedly needed when you invoke the script not from the project root. – x-yuri Jun 18 '19 at 18:24
  • 1
    what if it's inside a file that gets called multiple times? can I run django.setup() once and it will stay global? – elad silver Aug 26 '20 at 18:58
  • 1
    if someone uses this answer and uses Path to get path to file like this:`BASE_DIR = Path('').resolve().parent` i had to convert to string or else it wouldn't find the model `sys.path.append(str(BASE_DIR))` – António Caeiro Oct 01 '20 at 13:10
  • ImportError: attempted relative import beyond top-level package @António Caeiro – abhishek surela Jul 10 '22 at 23:03
15

This sounds like a great use case for Django Management commands. which has the added bonus you can run it scheduled from cron, direct from the commandline, or call from inside django. This gives the script full access to the same settings and environment variables as your main project.

If you move this into an appropriate directory - using store here as an example, not a suggestion, it should work.

store 
    management 
    __init__.py
        commands
        __init__.py 
        otherscript.py 
Withnail
  • 3,128
  • 2
  • 30
  • 47
2

I found the django-extensions package to be most useful. You can find it here

After installation and adding it to the installed apps, all you need to do is to create a directory called scripts, create a file and run it by python manage.py runscript file_name

Just remember that the file must have an entry point. That entry point is a method called run which has to be present and will run once you run python manage.py runscript file_name in the terminal

Ramtin
  • 3,058
  • 1
  • 22
  • 24
2

Django standalone script.

  • Place it in the same directory as manage.py file
  • Rename PROJECT_NAME to your project's name
import os

PROJECT_NAME = 'ENTER YOUR PROJECT NAME HERE'

def main():
    # import statemts
    # from app.models import Author,Category,Book
    
    # code logic - anything you want
    

if __name__ == '__main__':
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', '%s.settings' % PROJECT_NAME)
    import django
    django.setup()
    main()
RUGVED
  • 174
  • 3
  • 3
1

try to import from store_app.models - as the surrounding store folder is not a python module and should not be used when importing.

import django
from django.conf import settings

settings.configure(DEBUG=True)
django.setup()

from store_app.models import MyModel

update: i just noticed that you put that script next to your project folder - you should move it inside for this to work.

dahrens
  • 3,879
  • 1
  • 20
  • 38
  • Can't my_script be in a different package? – Ben RR Sep 27 '16 at 11:44
  • it can, but it depends on your path - a django project is usually not in the path, therefore i adviced you to move it. nevertheless - if you must not run besides django, you should go the way @Withnail mentioned. – dahrens Sep 27 '16 at 13:02
0
import django
from django.conf import settings
>>from store.store_app.apps import StoreAppConfig<<

This line can be deleted if "other_script.py" moves to the "store" folder & "settings.py" file inserts "other_script" name in "instaled_apps". Don't add "other_cript" to "instaled_apps" & change it to:

>>from store import settings
settings.configure(settings, DEBUG=True)
django.setup()<<

and in the end I think:

>>from store.store_app.models import MyModel<<

change this to:

>>from store_app.models import MyModel<<