Models¶
Status: Placeholder — to be developed. Last reviewed: — Reference structural sibling:
guidelines/ui/forms.md(component-style sectioning + length).
Scope (when this guideline lands)¶
Conventions for Django models: which abstract base to inherit from, field naming, choices vs enums, __str__ style, Meta ordering, soft-delete handling, when a custom manager is justified.
Out of scope (cross-refs)¶
- Migration generation and review →
guidelines/backend/migrations.md(placeholder). - Admin registration /
list_display→guidelines/backend/admin.md(placeholder). - Display strings (
verbose_name,help_text,choiceslabels — must be French source per Option B) →guidelines/i18n/translation-rules.md. - Practice FK / multi-tenant scoping rule: which models declare a
practiceFK and why →guidelines/security/multi-tenant-isolation.md(placeholder). - Entity / ownership / consolidation domain model specifics →
docs/entity-model.md(reference, not a guideline).
Sources to mine when writing this¶
apps/core/models.py—TimeStampedModel,AuditModel,SoftDeleteModeldefinitions and intended usage. Read class docstrings.- Models in well-curated apps:
apps/entities/models.py,apps/dentists/models.py,apps/practices/models.py(this last one has 99 model strings and is the test bed for many conventions). apps/register/models.py— recent comprehensive rewrite (BaseDocument + per-habitat concretes perroadmap/done/captable-improvements.md).
Starter hard rules to investigate¶
- Inherit from
TimeStampedModel(created_at/updated_at) by default. AddAuditModel(created_by/updated_by) when audit trail matters. AddSoftDeleteModelonly when records have legal/regulatory retention requirements. - Choice constants are uppercase identifiers:
STATUS_ACTIVE = 'active'(English keys, French labels via_('Actif')per i18n rule). - Field names are English snake_case:
first_name,is_active,birth_date. Display strings (verbose_name) are French. __str__returns a French user-friendly identifier (per i18n rule); not the technical PK.Meta.orderingis explicit for any model that appears in lists. Default to a stable, sensible order.
Decision points to settle¶
- Soft-delete vs hard-delete: which models warrant SoftDelete? Patient (legal), Procedure (legal), Dentist (probably hard-delete with end_date), …?
blank=True, null=Truepair: official Django convention isblank=Truefor forms +null=Trueonly for non-string fields. The codebase may have drifted; settle.- Custom managers vs class methods: when does a model deserve a manager? (e.g.,
Patient.objects.active()vsPatient.objects.filter(is_active=True).) - Model property vs computed field vs annotated: where does business-derived data live? Several apps have all three patterns.
Known deviations to look for during writing¶
- Models without
TimeStampedModelinheritance. - Choice tuples without constants (raw strings inline in choices=
[('active', _('Actif'))]). __str__returning English / technical text (would have been caught by the i18n convergence sweep — verify).
If found, file as roadmap/backlog/backend-models-drift-2026-MM.md.