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.