How to Add a Model
Developer guide for the Enezaframework. Part of the Developer documentation.
Table of Contents
- Overview
- Step 1: Pick a Base Model
- Step 2: Create the Model File
- Step 3: Declare Fields
- Step 4: Re-export in
models/__init__.py - Step 5: Migrate
- Common Pitfalls
- Change History
- Related Guides
Overview
Adding a model is the first step of every feature. This guide lists the atomic steps in order, so each one can be done and reviewed on its own. The complete chain after the model is covered in Developer Workflow.
flowchart TD
PICK[Pick a base model] --> FILE[Create models/<name>.py]
FILE --> FIELDS[Declare fields per conventions]
FIELDS --> EXPORT[Re-export in models/__init__.py]
EXPORT --> MIGRATE[makemigrations + migrate]
MIGRATE --> NEXT[Add views, menus, URLs]Step 1: Pick a Base Model
Choose the base that matches the record's role. The decision tree is in Base Models & Model Types.
| Record | Base |
|---|---|
| Master data with a business number | EnezaMaster |
| One-to-one detail of a master | EnezaMasterDetails |
| Document header with numbering | EnezaDocument |
| Document header without numbering | EnezaTransactionalTable |
| Document line item | EnezaDocumentLines |
| Setup/configuration row | EnezaSetup |
| Single-instance parameter | EnezaParameter |
| Anything else | EnezaGeneral |
Every model that inherits one of these bases also supports lifecycle hooks. Add @hook methods
directly to the model; no additional base or mixin is needed. See
Lifecycle Hooks (Events).
Step 2: Create the Model File
Create one file per model under the app's models/ package.
accountpayable/models/vendorgroup.py
# accountpayable/models/vendorgroup.py
from django.db import models
from enezaframework.models import EnezaSetup
class VendorGroup(EnezaSetup):
...
Use one file per model and name the file after the model in lowercase (vendorgroup.py for
VendorGroup). See Standardized App Structure.
Step 3: Declare Fields
Declare each field on its own line and follow the mandatory conventions in
Model Field Conventions: one field per line, a verbose_name on every
field, and a multi-line field call closed on its own aligned line.
# accountpayable/models/vendorgroup.py
from django.db import models
from enezaframework.models import EnezaSetup
class VendorGroup(EnezaSetup):
code = models.CharField(
max_length=50,
unique=True,
verbose_name="Code",
)
description = models.CharField(
max_length=255,
verbose_name="Description",
)
vendorpostinggroup = models.ForeignKey(
"VendorPostingGroup",
on_delete=models.PROTECT,
verbose_name="Vendor Posting Group",
)
class Meta:
verbose_name = "Vendor Group"
verbose_name_plural = "Vendor Groups"
def __str__(self):
return self.description
entity is added by the base class; do not declare it yourself.
Step 4: Re-export in models/__init__.py
The framework and other apps import from the models package root, so every model must be re-exported.
# accountpayable/models/__init__.py
from .vendorgroup import VendorGroup
from .vendorpostinggroup import VendorPostingGroup
Without this line, from accountpayable.models import VendorGroup fails even though the class exists.
This is the same rule the framework uses for its own package.
Step 5: Migrate
python manage.py makemigrations accountpayable
python manage.py migrate
Inspect the generated migration before applying it. For models that inherit a framework base, the
entity, audit, UUID primary key, and history table come from the base.
Common Pitfalls
- Forgetting the re-export. The class is not importable from the package root until it is in
models/__init__.py. - Assuming
EnezaModelhasentityoris_active.EnezaModelhas neither; each concrete base addsentity, andis_activeis opt-in per model. - Using the singular
EnezaMasterDetail. It is not re-exported; useEnezaMasterDetails. - Expecting
EnezaTransactionalTableto auto-number. It has noSequenceMixin; useEnezaDocumentwhen you need numbering. - Skipping
verbose_name. Every field must set it.
The user is solely responsible for testing and validating the model (for example by running the migrations in their environment); the developer/agent does not run the application.
Change History
Dated changes that affect this guide, taken from
docs/Release note/CHANGELOG.md and the release notes. For the
complete history, see the changelog.
No dated changes to the add-model steps or the models/__init__.py re-export rule appear in the
changelog for the 0.2.7–0.2.19 window.