Bradley Kirton's Blog

Published on Feb. 24, 2025

Go home

Django view dispatching

When developing Django applications, you often need views that handle multiple related actions on the same resource. Traditional approaches might lead to bloated views or unnecessary duplication across multiple view classes.

In this post, I'll share a practical pattern for organizing and dispatching different actions within a single Django view based on my experience building complex applications.

Let's consider a common scenario, managing a contact record that requires multiple operations:

  1. Updating basic contact details (name, email, phone)
  2. Managing company relationships for the contact

We can model the actions above using an enum.

class ContactSectionEnum(enum.StrEnum):
    """Models the contact sections."""

    DETAIL = enum.auto()
    COMPANIES = enum.auto()

We can then organise the view code around this enum.

  1. Render only the required section
  2. Apply only the required action

In order to achieve this we can use query params for dispatching within our view code.

class ContactManage(View):
    def get_section(self, request: HttpRequest) -> ContactSectionEnum:
        """Parse the section from the request query params."""
        section = ContactSectionEnum.DETAIL  # Use DETAIL as the default section
        section_raw = request.GET.get("s", "")

        if section_raw:
            try:
                section = ContactSectionEnum(section_raw)
            except:
                pass

        return section

    def get(self, request: HttpRequest, contact_id: int) -> HttpResponse:
        section = self.get_section(request=request)
        contact = get_object_or_404(db_models.Contact.objects.filter(pk=contact_id))

        if section is ContactSectionEnum.DETAIL:
            section_context = self.get_detail_context_data(contact_id=contact_id, contact=contact)
        elif section is ContactSectionEnum.COMPANIES:
            section_context = self.get_companies_context_data(contact_id=contact_id, contact=contact)
        else:
            raise ValueError(f"Invalid section {section}")

        context = self.get_context_data(contact_id=contact_id, contact=contact)
        context =| section_context

        return render(request, "contact_manage.html", context)

    def post(self, request: HttpRequest, contact_id: int) -> HttpResponse:
        section = self.get_section(request=request)
        contact = get_object_or_404(db_models.Contact.objects.filter(pk=contact_id))

        if section is ContactSectionEnum.DETAIL:
            return self.process_update_detail(request=request, contact_id=contact_id, contact=contact)
        elif section is ContactSectionEnum.COMPANIES:
            return self.process_update_companies(request=request, contact_id=contact_id, contact=contact)
        else:
            raise ValueError(f"Invalid section {section}")

    def process_update_detail(self, request: HttpRequest, contact_id: int, contact: db_models.Contact) -> HttpResponse: ...
    def process_update_companies(self, request: HttpRequest, contact_id: int, contact: db_models.Contact) -> HttpResponse: ...