Search code examples
djangodjango-generic-views

Why can you import UpdateView in "multiple ways"


Why do both of the following ways of importing UpdateView work?:

  • 1. from django.views.generic import UpdateView
  • 2. from django.views.generic.edit import UpdateView

I was assuming 2. was the correct way, and 1. would not work, but from testing both work.


Solution

  • What you see here is quite common (at least in some Python packages). If you define a .py file, that acts as a module. For example the django.views.generic.edit module maps on the django/views/generic/edit.py file [GitHub].

    A directory is a Python module as well (due to the __init__.py file), but it does not contain any elements by default, hence that would mean that django.views.generic would be empty.

    If we take a look at the django/views/generic/__init__.py file [GitHub], we see:

    from django.views.generic.base import RedirectView, TemplateView, View
    # ...
    from django.views.generic.edit import (
        CreateView, DeleteView, FormView, UpdateView,
    )
    # ...
    
    __all__ = [
        'View', 'TemplateView', 'RedirectView', 'ArchiveIndexView',
        'YearArchiveView', 'MonthArchiveView', 'WeekArchiveView', 'DayArchiveView',
        'TodayArchiveView', 'DateDetailView', 'DetailView', 'FormView',
        'CreateView', 'UpdateView', 'DeleteView', 'ListView', 'GenericViewError',
    ]
    
    # ...

    This thus imports the UpdateView from the generic.py file, and re-exports the class.

    You thus can reference to the class in two ways: through the module defined by the generic.py file, or through the re-export of the module of the directory, specified through the __init__.py file.

    This is typically done to export a portion of the items that are defined in the files, export these under a more convenient name, or provide some extra classes at the module level (for example the __init__.py file defines the GenericViewError error).

    This directory-level module thus "groups" interesting views together. For example the FormMixin is not exported at this level. The __init__.py here groups (popular) class-based views together, whereas the mixins, that are typically used to define such generic views, are still specific to a file.