Skip to content

Accounts — signals

Responsibilities

The accounts signals initialize required related records when a new user is created.

They are responsible for:

  • creating the default UserProfile
  • creating the default UserSettings
  • creating the default UserWorkSchedule
  • ensuring a stable set of seven UserWorkDay rows exists

They are not responsible for:

  • complex business workflows
  • permission logic
  • account onboarding decisions
  • authentication/session logic
  • schedule editing rules

In this app, signals are used only for lightweight, automatic related-model setup.


Main signal handlers

Triggered when a User is created.

  • Signal
  • post_save
  • Sender
  • User
  • Trigger condition
  • runs only when created=True
  • Behavior
  • creates UserProfile if missing
  • creates UserSettings if missing
  • creates UserWorkSchedule if missing
  • ensures weekday rows 0..6 exist in UserWorkDay
  • Idempotency
  • uses get_or_create
  • only inserts missing UserWorkDay rows

This guarantees a new user immediately has the related records needed by the frontend and API.


Why this signal exists

The frontend and API expect these related rows to exist consistently:

  • user.profile
  • user.settings
  • user.work_schedule
  • exactly 7 work_schedule.days

Without this signal, many endpoints would need defensive get_or_create() logic or risk missing-related-object errors.

The signal keeps the default user state stable from the moment the account is created.


UserProfile

Created automatically for every new user.

Purpose: - stores workforce identity and operational profile data


UserSettings

Created automatically for every new user.

Purpose: - stores UI settings and preference overrides


UserWorkSchedule

Created automatically for every new user.

Purpose: - stores the user’s weekly schedule container


UserWorkDay

Ensured as seven rows for weekdays 0..6.

Purpose: - provides a stable weekly structure for schedule editing and hour calculations

This design avoids sparse or partially initialized schedules.


Signal relationship overview

flowchart TD
    User[User created]
    Signal[post_save signal: ensure_user_related_models]

    UserProfile[UserProfile]
    UserSettings[UserSettings]
    UserWorkSchedule[UserWorkSchedule]
    UserWorkDay[UserWorkDay x 7]

    User --> Signal
    Signal --> UserProfile
    Signal --> UserSettings
    Signal --> UserWorkSchedule
    Signal --> UserWorkDay

Execution flow

sequenceDiagram
    participant App as User creation
    participant Signal as ensure_user_related_models
    participant Profile as UserProfile
    participant Settings as UserSettings
    participant Schedule as UserWorkSchedule
    participant Days as UserWorkDay

    App->>Signal: post_save(created=True)
    Signal->>Profile: get_or_create(user=instance)
    Signal->>Settings: get_or_create(user=instance)
    Signal->>Schedule: get_or_create(user=instance)
    Signal->>Days: check existing weekdays
    Signal->>Days: bulk_create missing 0..6 rows

idempotency and safety

The signal is intentionally designed to be safe against duplicate creation: • UserProfile.objects.get_or_create(...) • UserSettings.objects.get_or_create(...) • UserWorkSchedule.objects.get_or_create(...)

For UserWorkDay, it: 1. checks which weekdays already exist 2. computes missing weekdays 3. bulk creates only the missing rows

This means: • the signal is safe on first create • repeated saves do not create duplicates • the weekly schedule remains complete even if partially corrupted and repaired via the same logic elsewhere


App registration requirement

For the signal to run reliably, the signal module must be imported during app startup.

Typical pattern:

# accounts/apps.py
from django.apps import AppConfig


class AccountsConfig(AppConfig):
    name = "accounts"

    def ready(self):
        import accounts.signals
Without this registration, the signal handler may never be connected.