Skip to content

WizardView.get_context_data() does not compatible to TemplateView.get_context_data() #292

@denisw

Description

@denisw

Summary

WizardView defines get_context_data() with the following signature:

def get_context_data(self, form, **kwargs)

However, in its superclass TemplateView (or, specifically, ContextMixin) it has the following signature:

def get_context_data(self, **kwargs)

This means that the override in WizardView is incompatible because it breaks the Liskov substitution principle: form is required by WizardView, but not by TemplateView.

Why it matters

  • Code designed to work with any TemplateView (such as a mixin that overrides get_context_data() to add an additional entry) may not work with WizardView.

  • When the user overrides get_context_data() in a WizardView, type checkers like Ty complain about the override being incompatible, no matter whether you define it with form (incompatible with ContextMixin) or without (incompatible with WizardView).

  • As a consequence of the above, it is basically impossible to write a type stub for WizardView.get_context_data(). This is a blocker for adding typings to Typeshed or directly to Formtools.

Proposed solution

Change the signature of WizardView.get_context_data() to:

def  get_context_data(self, *, form=None, **kwargs)

That is, make form an optional keyword-only parameter. This is compatible with the plain **kwargs defined in ContextMixin because it allows form not to be passed, and because both versions don't accept any positional arguments.

For convenience, a get_context_data_for_step(self, form, **kwargs) method could be provided, which would called by get_context_data() either with the received form or self.get_form() (same logic as currently in render()):

def get_context_data(self, *, form=None, **kwargs):
    form = form or self.get_form()  # moved here from render()
    context = super().get_context_data(form=form, **kwargs)
    context.update(self.get_context_data_for_step(form, **kwargs))
    ...

def get_context_data_for_step(self, *, form, **kwargs):
    return {}  # default implementation

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions