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:

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.