8

Following this guide, I am able to use models outside of Django with the following file structure by calling python main.py.

├── data
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   └── models.py
├── main.py
├── manage.py
└── settings.py

where main.py looks like this:

import os, django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')

django.setup()
from data.models import Foo, Bar #...

print(Foo.objects.all()) #this works fine

What I want to do is turn this into a "package" called db that looks like this:

    ├── data
    │   ├── __init__.py
    │   ├── migrations
    │   │   └── __init__.py
    │   └── models.py
    ├── __init__.py 
    ├── manage.py
    └── settings.py

And in the __init__.py of the db package, I want to do this:

import os, django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings')

django.setup()
from data.models import Foo, Bar # ...
from django.db import connection

__all__ = [
    'connection',
    'Foo',
    'Bar', 
    #...
]

So I can call the db package from test.py (which is in the same directory as db) like this:

import db

print(db.Foo.objects.all()) # this throws an error "no module named data"

or like this:

from db import Foo

print(Foo.objects.all()) # this throws an error "no module named settings"

Is there a way I can use Django's models without having to call: os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings') django.setup()

on every page that uses a model?

What am I missing here?

Dave Mackey
  • 4,306
  • 21
  • 78
  • 136
Lord Elrond
  • 13,430
  • 7
  • 40
  • 80

1 Answers1

1

If you check out how Django apps are loaded I think you need to run your setup in your application’s models.py or models/init.py and not in db/__init__.py

When Django starts, django.setup() is responsible for populating the application registry.

setup(set_prefix=True) Configures Django by:

Loading the settings. Setting up logging. If set_prefix is True, setting the URL resolver script prefix to FORCE_SCRIPT_NAME if defined, or / otherwise. Initializing the application registry. This function is called automatically:

When running an HTTP server via Django’s WSGI support. When invoking a management command. It must be called explicitly in other cases, for instance in plain Python scripts.

The application registry is initialized in three stages. At each stage, Django processes all applications in the order of INSTALLED_APPS.

First Django imports each item in INSTALLED_APPS.

If it’s an application configuration class, Django imports the root package of the application, defined by its name attribute. If it’s a Python package, Django creates a default application configuration.

At this stage, your code shouldn’t import any models!

In other words, your applications’ root packages and the modules that define your application configuration classes shouldn’t import any models, even indirectly.

Strictly speaking, Django allows importing models once their application configuration is loaded. However, in order to avoid needless constraints on the order of INSTALLED_APPS, it’s strongly recommended not import any models at this stage.

Once this stage completes, APIs that operate on application configurations such as get_app_config() become usable.

Then Django attempts to import the models submodule of each application, if there is one.

You must define or import all models in your application’s models.py or models/__init__.py. Otherwise, the application registry may not be fully populated at this point, which could cause the ORM to malfunction.

Once this stage completes, APIs that operate on models such as get_model() become usable.

Finally Django runs the ready() method of each application configuration.

Scott Skiles
  • 3,647
  • 6
  • 40
  • 64