简体   繁体   中英

Importing django modules without settings being configured

Consider following simple scenario. Given File common.py

from data import MyModel    # This is a Model inheriting django.db.models.Model

def foo(bar: MyModel):
    print(bar)

def other_func():
    pass

And given file main.py , using one of the functions in common, but not the other one that depends on django.

import common
from django.conf import settings

if __name__ == "__main__":
    config_file = sys.argv[1]   # This would be argparser in real life scenario
    settings.configure(....config_file...)
    common.other_func()

This format is how i believe most main functions would look like since settings often depend on environment variable, config files or command line arguments.

I'm not able to run this code because any time one simply imports a django model, it attempts to load settings and access the database. With following error:

  File "models.py", line 33, in <module>
    class MyModel(models.Model):
  File "django/db/models/base.py", line 108, in __new__
    app_config = apps.get_containing_app_config(module)
  File "django/apps/registry.py", line 253, in get_containing_app_config
    self.check_apps_ready()
  File "django/apps/registry.py", line 135, in check_apps_ready
    settings.INSTALLED_APPS
  File "django/conf/__init__.py", line 84, in __getattr__
    self._setup(name)
  File "django/conf/__init__.py", line 65, in _setup
    raise ImproperlyConfigured(
django.core.exceptions.ImproperlyConfigured: 
      Requested setting INSTALLED_APPS, but settings are not configured. 
      You must either define the environment variable DJANGO_SETTINGS_MODULE 
       or call settings.configure() before accessing settings.

Next attempt, move the settings.configure above the imports inside main.py ,

from django.conf import settings
settings.configure(.....)
import common

This works, but it infects the entire code base , making it impossible to import common from any other modules and in unit tests. Unless every single potential entrypoint is guaranteed to also call settings.configure first .

Last workaround i found is to put all django imports inside each function using them. Like this

def foo(bar):
    from data import MyModel
    print(bar)

But this is not possible to do if you want to use them as type-annotations on the function signature. It also looks very odd, requires lots of duplicate imports in each function, and doesn't play nice with some IDE autocompletion or linter features.


So to conclude my question:

How can one work with django model imports in the code base, without having to call settings.configure() , until the models are actually used during runtime to query the database ?

If you only use MyModel for the type annotation, you can use typing.TYPE_CHECKING .

# common.py
import typing

if typing.TYPE_CHECKING:
    from data import MyModel

This will only be imported during static type checking, not at the runtime.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM