Django models outside of models.py
By default, Django models are
placed in models.py
files inside apps. However, this
single file can outgrow the needs of large apps that require
storing dozens or hundreds of models. There are three techniques
you can use to deallocate Django models from models.py
files inside apps.
Django models inside apps in the models folder
The first technique to store
Django models outside of models.py
files is to create
a folder named models
-- inside the same app --
declare class models in standalone files in this folder and import
the classes through this new folder's __init__
file.
Listing 7-42 shows an app folder layout for this type of model
deployment.
Listing 7-42. Django apps with models stored under models directory
+---+ | +-stores(app)-+ +-__init__.py +-models.py +-tests.py +-views.py +-apps.py +-models-+ | +-__init__.py +-menus.py +-equipment.py +-personnel.py
Notice in listing 7-42 that
alongside the standard models.py
file is a
models
folder. Next, inside the models
folder are multiple .py
files with Django models
declared as they would typically be done inside
models.py
. You can have as many models as needed in
each .py
file and as many .py
files as
you deem necessary (e.g. one model per file).
However, the
__init__
file inside this new models
folder does require additional attention. While
__init__
files are typically left empty, in this case,
the __init__
file must make a relative import for each
of the models -- inside .py
files -- to make them
visible to the app. For example, if the menus.py
file
contains the Breakfast
model class, the
__init__
file must declare the line from .menus
import Breakfast
. This one-line syntax -- from
.<file> import <model_class>
-- must be used in
__init__.py
for every model declared in
.py
files inside the models
folder.
With this layout you're able to
place Django models outside of a single models.py
file, but the following points apply to this first technique to
relocate Django models:
- The sub-folder must be named
models
.- Because themodels.py
file is inspected by default (as the Python path<app>.models
), it requires an identically named Python path<app>.models
to detect models -- with the__init__
file doing the rest of the import work. So beware any other folder name different thanmodels
won't work with this configuration -- the next technique to configure models outsidemodels.py
a solution to using a different folder name. - Declaring an app as part of
INSTALLED_APPS
is sufficient, so long as the__init__
file performs the correct relative imports.- So long as an app is declared as part ofINSTALLED_APPS
insettings.py
, it's sufficient for Django to detect any models declared inside themodels
folder as described in listing 7-42. Just take care of relatively importing all models in the__init__.py
file. - The app name for every model is determined automatically.- Since the
models
folder is nested inside an app, all the models inside this folder receive the app name configured in theapps.py
file for the app. Although you can use the meta classapp_label
option to explicitly assign an app to a model -- as described earlier in the Meta class options section -- it's redundant in this case because the models receive the same app name they're in, including the placement of their migrations files. - The models are accessible as if they were in
models.py
.- Athough the models are placed in different files, the Python access path remainsapp.models
, so the models are accessible as if they were inmodels.py
(e.g. to access theBreakfast
model class inside themenus.py
file, you would still usefrom <app>.models import Breakfast
from other parts of an application).
Django models inside apps in custom folders
A second technique to declare
models outside models.py
files is to use custom
folders inside an app. This requires using the main
models.py
file as the import mechanism and also
requires using longer access paths for models. Listing 7-43 shows
an app folder layout with custom folders for models.
Listing 7-43. Django apps with models stored under custom directories
+---+ | +-stores(app)-+ +-__init__.py +-models.py +-tests.py +-views.py +-apps.py +-menus+ | +-__init__.py | +-breakfast.py |
+-equipment+
+-__init__.py +-kitchen.py
As you can listing 7-43 the app
now has multiple sub-folders, where each folder contains multiple
.py
files with Django models declared as they would
typically be done inside models.py
. (i.e.
breakfast.py
and kitchen.py
in listing
7-43 contain model classes).
Since Django only looks for
models under the Python path <app>.models
, you
must declare a relative import in the main models.py
file -- for each of the models inside sub-folders -- to make them
visible to the app. For example, if the Breakfast
model class is inside the menus
sub-folder file and
breakfast.py
file, the main models.py
file must declare the line from .menus.breakfast import
Breakfast
. This one-line syntax -- from
.<sub_folder>.<file> import <model_class>
-- must be used in models.py
for every model declared
in sub-folders inside an app.
Because the
models.py
file uses a relative import path to the
models themselves, this alters the standard Django Python path to
access models -- from <app>.models...
-- and
requires a longer path: from
<app>.models.<sub_folder>.<file>...
.Other
than this change in import paths, the remaining configuration
options for models have no change in behavior (i.e.
INSTALLED_APPS
, model app name).
Django models outside apps & model assignment to other apps
A third technique available for Django models is to declare them completely outside of apps or inclusively assign Django models to a different app than the one in which they're declared. So what does it means to 'assign models to an app' ? It means just that, you can declare models outside of apps or in a given app, but change the app a model belongs to.
Although I don't recommend this technique because it can lead to confusion, it does provide a different solution that I'll describe for the sake of completeness.
This technique requires you
provide models an explicit app name through the meta class app_label
option so they're assigned to an app. When
Django detects a model declares the meta app_label
option, this takes the highest precedent to assign a model its app
name. So even if a model is declared inside a random folder named
common
or an app named items
, if a
model's meta app_label
value is set to
stores
, the model is assigned to the
stores
app, irrespective of its location.
The confusing aspect of using the
app_label
option is due to the influence an app name
has on Django models. For example, an app name is used to give a a
model's database table name prefix and it's also used to determine
the location of a model's migration files. So if you define a model
inside a folder named common
with the meta class
app_label='stores'
, the model will end up up belonging
to the stores
app -- along with its migration files
and a prefix table app name stores
-- even though it's
declared in the common
folder.
This last technique although flexible, as I've just explained can also lead to unintuitive outcomes in the naming and placement of Django model constructs.