Views¶
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 class-based views: which mixins to use for which view type, HTMX response handling, permission/access patterns, where business logic lives (services vs views), naming.
Out of scope (cross-refs)¶
- Search / sort / filter mixin contract (
SortableFilterableListMixin, scope filters, URL/cookie state) →guidelines/ui/search-sort-filter.md. This file covers the broader CBV conventions; sort/filter is documented there. - Form construction (Form / ModelForm classes,
clean_*, validation placement) →guidelines/backend/forms.md(placeholder). - Template rendering (list / detail / form layouts) →
guidelines/ui/lists.md,detail-pages.md,forms.md. - Queryset scoping for multi-tenancy →
guidelines/security/multi-tenant-isolation.md(placeholder). This file references the mixin; multi-tenant.md owns the rule. - Permission decorators / mixins (LoginRequiredMixin, FeatureRequiredMixin, custom access checks) →
guidelines/security/auth-and-permissions.md(placeholder).
Sources to mine when writing this¶
apps/core/mixins.py—SortableFilterableListMixin,HtmxResponseMixin,MultiPracticeFilterMixin,PeriodFilterMixin,FeatureRequiredMixin. Read all class docstrings.- Reference views from apps with the cleanest pattern:
apps/practices/views.py,apps/dentists/views.py,apps/register/views.py. apps/imports/views.py— recently rewritten with constants pattern + i18n fixes (commit8a023fd); good reference formessages.*()usage.apps/finance/views.py— usesFinanceFilterMixin(the known deviation tracked inroadmap/backlog/finance-filter-unify.md).apps/websites/views_cms.py— DRF-style API view; out of scope but worth noting.
Starter hard rules to investigate¶
- Compose the blessed mixins: list views inherit
HtmxResponseMixin + FeatureRequiredMixin + filter mixins + SortableFilterableListMixin + ListView. Mixin order matters (Django MRO). - Business logic lives in
apps/<app>/services/, not in views. Views are thin: parse → call service → render. - HTMX responses go through
HtmxResponseMixin— never hand-roll partial vs full template selection. messages.*()calls usegettext_lazy-wrapped constants for repeated messages (perguidelines/i18n/translation-rules.mdIMPORT_STARTED_MSG pattern).get_context_datais for context only — no business logic, no DB queries beyond what the queryset already loads.
Decision points to settle¶
- Service-layer naming:
apps/<app>/services/<name>.pyfiles vsapps/<app>/services.pysingle module. Codebase has both; pick. get_queryset()vs classqueryset: when to use each. Multi-tenant filtering forcesget_queryset().- Function-based views: are they ever acceptable? (sync sample view in
apps/sync/uses@require_POST+ function — document the rule.) - DRF vs Django views for
apps/websites/: keep separate or write a shared base?
Known deviations to look for during writing¶
- Views with
transaction.atomic+ business logic inline (should be in service). - Views overriding
dispatchfor permission checks instead of using a mixin. - List views that bypass
SortableFilterableListMixinfor "simplicity" (track persearch-sort-filter.mdKnown deviations).
If found, file as roadmap/backlog/backend-views-drift-2026-MM.md.