Skip to content

Mixins

The core.mixins layer provides reusable DRF-oriented building blocks for viewsets.

These mixins are designed to reduce duplication and enforce common backend conventions, especially around:

  • organization scoping
  • audit fields
  • create/update behavior

They are infrastructure helpers, not business logic containers.


Purpose

Mixins exist to:

  • standardize repeated DRF patterns
  • keep viewsets small and consistent
  • reduce boilerplate in feature apps
  • enforce safe defaults

They are especially useful when many apps share the same structural needs.


Current Mixins

The current mixin layer includes:

  • OrgScopedViewSetMixin
  • AuditFieldsViewSetMixin

OrgScopedViewSetMixin

This mixin ensures that a viewset is automatically scoped to the current organization.

Responsibilities

  • filter queryset by request.org
  • attach org automatically on create

Behavior

Queryset scoping

If request.org exists:

  • the queryset is filtered by the configured org field

If request.org does not exist:

  • an empty queryset is returned

This prevents accidental cross-org access.

Create behavior

On create:

  • the mixin injects the current org into serializer.save(...)

If org is missing:

  • it raises PermissionDenied

Default org field

By default, the mixin assumes the model field is:

org

This can be customized using:

org_field = "your_custom_field"


Typical usage

Use this mixin when:

  • the model is org-scoped
  • the endpoint should always operate within the current org
  • the org should never come from client input

AuditFieldsViewSetMixin

This mixin automatically sets audit fields on create and update.

Responsibilities

  • set created_by on create if supported by model
  • set updated_by on create and update if supported by model

Behavior

On create:

  • if model has created_by, it is set to request.user
  • if model has updated_by, it is also set to request.user

On update:

  • if model has updated_by, it is set to request.user

Model detection

The mixin checks whether the serializer’s model contains the expected audit fields.

This allows the mixin to work safely across different models without requiring explicit configuration.


Why These Mixins Exist

Without mixins, many viewsets would repeat the same logic:

  • filter by org
  • inject org on create
  • set created_by / updated_by
  • handle missing org state

The mixins centralize those patterns and make behavior more predictable.


Relationship to Other Layers

Permissions

Mixins assume the request has already passed permission checks such as:

  • HasCurrentOrg

They do not replace permission enforcement.


Services

Mixins do not implement business logic.

They only help with common DRF viewset behavior.

All domain rules should still live in services.


Usage Example

A typical org-scoped audited viewset might combine both mixins:

  • OrgScopedViewSetMixin
  • AuditFieldsViewSetMixin

This gives:

  • automatic org filtering
  • automatic audit field population

without repeating the same code in every app.


Execution Flow

flowchart TD
    A[Request enters viewset] --> B[Permissions validate request.org]
    B --> C[OrgScopedViewSetMixin filters queryset]
    C --> D[Serializer validated]
    D --> E[AuditFieldsViewSetMixin injects audit user]
    E --> F[Object saved]

What Mixins Should NOT Do

Mixins should not:

  • perform business authorization checks
  • contain domain rules
  • write audit logs
  • replace service-layer validation
  • parse request headers
  • implement feature-specific behavior

Best Practices

Use OrgScopedViewSetMixin when:

  • model is org-scoped
  • current org must be enforced automatically
  • org should never be provided by the client

Use AuditFieldsViewSetMixin when:

  • model includes created_by and/or updated_by
  • request user should be attached automatically

Combine them when appropriate

Many internal CRUD viewsets will benefit from using both.


Common Mistakes

Putting business logic in mixins

Mixins should stay generic and reusable.

Using mixins without proper permissions

If HasCurrentOrg is missing, org scoping may fail or return empty querysets.

Relying on mixins instead of services

Mixins help with DRF mechanics, not domain workflows.


Testing Strategy

Mixins are tested directly in the core test suite.

Tests verify:

  • queryset scoping by org
  • create behavior with and without org
  • created_by / updated_by assignment
  • no-op behavior when audit fields are absent

Benefits

The mixin layer provides:

  • less boilerplate
  • safer defaults
  • more consistent CRUD behavior
  • easier maintenance across apps

Summary

The core.mixins layer provides reusable DRF helpers for:

  • org scoping
  • audit field assignment

These mixins help keep viewsets clean while preserving the architecture principle that business logic belongs in services.