示例#1
0
class YearMixin(ChildViewMixin, dates.YearMixin):
    """
    Mixin for views manipulating year-based data.
    """

    year_format = delegate_to_parent('year_format', '%Y')
    year = delegate_to_parent('year')
示例#2
0
class WeekMixin(ChildViewMixin, dates.WeekMixin):
    """
    Mixin for views manipulating week-based data.
    """

    week_format = delegate_to_parent('week_format', '%U')
    week = delegate_to_parent('week')
示例#3
0
class DateMixin(ChildViewMixin, dates.DateMixin):
    """
    Mixin class for views manipulating date-based data.
    """

    date_field = delegate_to_parent('date_field')
    allow_future = delegate_to_parent('allow_future', False)
示例#4
0
class DayMixin(ChildViewMixin, dates.DayMixin):
    """
    Mixin for views manipulating day-based data.
    """

    day_format = delegate_to_parent('day_format', '%d')
    day = delegate_to_parent('day')
示例#5
0
class MonthMixin(ChildViewMixin, dates.MonthMixin):
    """
    Mixin for views manipulating month-based data.
    """

    month_format = delegate_to_parent('month_format', '%b')
    month = delegate_to_parent('month')
示例#6
0
class CanCreateMixin:
    """
    Adds the can_create() method which is called before get() and post() to check
    if the request is valid or not.
    """
    check_permissions = delegate_to_parent('check_permissions', False)
    raise_404_on_permission_error = delegate_to_parent('check_permissions', True)

    def get(self, request, *args, **kwargs):
        return (_check_permission_then_go(self, 'create') or
                super().get(request, args, kwargs))

    def post(self, request, *args, **kwargs):
        return (_check_permission_then_go(self, 'create') or
                super().post(request, args, kwargs))

    def can_create(self):
        """
        Return True if the current user can create `self.object` and False
        otherwise.

        This method tries to execute the parent's can_edit method. If it does
        not exist, it uses :func:`viewpack.permissions.can_edit`.
        """
        if not self.check_permissions:
            return True
        elif hasattr(self.parent, 'can_create'):
            return self.parent.can_create(self.object)
        else:
            return permissions.can_create(self.object, self.request.user)
示例#7
0
class TemplateResponseMixin(ChildViewMixin,
                            ParentTemplateNamesMixin,
                            TemplateResponseEndpointMixin,
                            base.TemplateResponseMixin):
    """
    A mixin that can be used to render a template.
    """

    # template_name = None
    template_engine = delegate_to_parent('template_engine')
    response_class = delegate_to_parent('response_class', TemplateResponse)
    template_extension = delegate_to_parent('template_extension', '.html')
    content_type = delegate_to_parent('content_type')
示例#8
0
class DetailView(CanViewMixin, SingleObjectTemplateResponseMixin,
                 SingleObjectMixin, detail.DetailView):
    """
    Render a "detail" view of an object.

    By default this is a model instance looked up from `self.queryset`, but the
    view will support display of *any* object by overriding `self.get_object()`.

    It looks up all attributes related to the detail view in the parent object,
    if not defined in the view class.
    """

    check_permissions = delegate_to_parent('check_permissions', False)
    raise_404_on_permission_error = delegate_to_parent('check_permissions',
                                                       True)
示例#9
0
class YearArchiveView(MultipleObjectTemplateResponseMixin,
                      dates.YearArchiveView):
    """
    List of objects published in a given year.
    """

    make_object_list = delegate_to_parent('make_object_list', False)
示例#10
0
class ArchiveIndexView(MultipleObjectTemplateResponseMixin,
                       dates.ArchiveIndexView):
    """
    Top-level archive of date-based items.
    """

    allow_empty = delegate_to_parent('allow_empty', False)
示例#11
0
class CreateView(SingleObjectTemplateResponseMixin, ModelFormMixin,
                 edit.CreateView):
    """
    View for creating a new object instance, with a response rendered by
    template.
    """
    template_name_suffix = delegate_to_parent('template_name_suffix', '_form')
示例#12
0
class TemplateResponsePackMixin(TemplateResponseMixin):
    """
    Add <template_basename><sub-view name>.<template_extension> to the list of
    templates.

    <sub-view name> is the name of the child view that is going to process the
    current request.

    This method only work if the child views inherit from the classes in
    :mod:`viewpack.views`. Theses classes inherit from Django built-in classes,
    and have the same API, but they insert hooks to search for some default
    values in the parent classes.
    """

    template_basename = delegate_to_parent('template_basename')
    template_extension = delegate_to_parent('template_extension', '.html')

    @lazy
    def template_extension_normalized(self):
        """
        Normalized template extension.

        An empty extension remains empty. Other extensions are normalized to
        start with a dot.
        """
        template_extension = self.template_extension
        if template_extension:
            template_extension = '.' + template_extension.lstrip('.')
        return template_extension

    def get_template_names(self, view_name):
        # Try default implementation that relies on the variable template_name
        # being set.
        try:
            names = super().get_template_names()
        except ImproperlyConfigured:
            if self.template_basename is None:
                raise
            names = []

        # Now we construct a template name from the given view_name and template
        # extension.
        if self.template_basename:
            names.append('%s%s%s' % (self.template_basename, view_name,
                                     self.template_extension_normalized))

        return names
示例#13
0
class MultipleObjectMixin(ContextMixin, list_.MultipleObjectMixin):
    """
    A mixin for views manipulating multiple objects.
    """

    allow_empty = delegate_to_parent('allow_empty', True)
    queryset = delegate_to_parent('queryset')
    model = delegate_to_parent('model')
    paginate_by = delegate_to_parent('paginate_by')
    paginate_orphans = delegate_to_parent('paginate_orphans', 0)
    context_object_name = delegate_to_parent('context_object_name')
    paginator_class = delegate_to_parent('paginator_class', Paginator)
    page_kwarg = delegate_to_parent('page_kwarg', 'page')
    ordering = delegate_to_parent('ordering')
示例#14
0
class SingleObjectMixin(ContextMixin, detail.SingleObjectMixin):
    """
    Provides the ability to retrieve a single object for further manipulation.
    """

    model = delegate_to_parent('model')
    queryset = delegate_to_parent('queryset')
    slug_field = delegate_to_parent('slug', 'slug')
    context_object_name = delegate_to_parent('context_object_name')
    slug_url_kwarg = delegate_to_parent('slug_url_kwarg', 'slug')
    pk_url_kwarg = delegate_to_parent('pk_url_kwarg', 'pk')
    query_pk_and_slug = delegate_to_parent('query_pk_and_slug', False)

    def get_object(self, queryset=None):
        if 'object' in self.__dict__:
            return self.object
        try:
            return self.parent.get_object(queryset)
        except (AttributeError, NotImplementedError):
            return super().get_object(queryset)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)

        if self.object:
            obj = self.object
            for parent in self.parents:
                name = getattr(parent, 'object_context_name', None)
                if name is None:
                    name = parent.model.__name__.lower()
                context.setdefault(name, obj)

        return context
示例#15
0
class SingleObjectTemplateResponseMixin(
        TemplateResponseMixin, detail.SingleObjectTemplateResponseMixin):

    # template_name_suffix = '_detail'
    template_name_field = delegate_to_parent('template_name_field')

    def get_template_names(self):
        # We mostly copy Django's implementation but insert the given template
        # extension instead of the hard-coded .html
        try:
            names = super().get_template_names()
        except ImproperlyConfigured:
            names = []
            extension = self.template_extension
            extension = '.' + extension.lstrip('.') if extension else extension

            if self.object and self.template_name_field:
                name = getattr(self.object, self.template_name_field, None)
                if name:
                    names.insert(0, name)

            if isinstance(self.object, models.Model):
                object_meta = self.object._meta
                if self.object._deferred:
                    object_meta = self.object._meta.proxy_for_model._meta
                names.append("%s/%s%s%s" % (
                    object_meta.app_label,
                    object_meta.model_name,
                    self.template_name_suffix,
                    extension,
                ))
            elif hasattr(self,
                         'model') and self.model is not None and issubclass(
                             self.model, models.Model):
                names.append(
                    "%s/%s%s%s" %
                    (self.model._meta.app_label, self.model._meta.model_name,
                     self.template_name_suffix, extension))

            if not names:
                raise

        names.extend(self.get_parent_template_names())
        return names
示例#16
0
class ViewPack(ChildViewMixin, View, metaclass=ViewPackMeta):
    """
    A parent view that dispatches to one child by asking each child if it
    accepts the given request.
    """
    #: Name of the child view that it should dispatch to
    dispatch_to = delegate_to_parent('dispatch_to')

    #: initkwargs that should be passed to class-based child views
    initkwargs = delegate_to_parent('initkwargs')

    #: Instance of the child view object responsible to respond to the request.
    #: This value is method-based, this attribute is set to None.
    child_view_object = None

    def __init__(self, dispatch_to=None, **kwargs):
        self.dispatch_to = dispatch_to
        super().__init__(**kwargs)

    @classmethod
    def as_view(self, dispatch_to=None, initkwargs=None, **initkwargs_):
        """
        Return a child view as a view function.

        Since group views comprises several different sub-views, it necessary
        to tell which view should be chosen. It is probably more convenient to
        register the ViewPack urls using the :func:`ViewPack.as_include`
        class method.

        It accepts two function signatures::

            ViewPack.as_view(view_name, **kwargs)
            ViewPack.as_view(view_name, initkwargs, **kwargs)

        In the first, the kwargs are passed to the ViewPack and in the second
        they are passed to the sub-view, it is a class based view.
        """
        if dispatch_to is None:
            raise RuntimeError(
                'ViewGroups views require a second parameter with the '
                'associated child view.\n'
                'Since they catch multiple urls, it is more convenient to '
                'register the urlpattenrs using ViewPack.as_include():\n')

        view = super().as_view(dispatch_to=dispatch_to,
                               initkwargs=initkwargs,
                               **initkwargs_)
        return view

    @classmethod
    def as_include(cls, initkwargs=None, *, namespace=None):
        """
        Register views as an include urlpatterns

        Example::

            urlpatterns = [
                url(r'^foo/', FooViewGroup.as_include(name='foo')),
            ]

        Args:
            initkwargs:
                A dictionary with the initial keyword args passed to the view
                constructor.
        Keyword args:
            namespace:
                Base name of the view. Each child view is registered by joining
                name with the child view own name.
        """

        app_name = get_app_name(cls)
        patterns = cls.as_include_patterns(initkwargs, app_name=app_name)
        includes = include(URLModule(patterns, app_name), namespace=namespace)
        return includes

    @classmethod
    def as_include_patterns(cls,
                            initkwargs=None,
                            *,
                            prefix=None,
                            app_name=None):
        """
        Return a list of url patterns for view.
        """

        if app_name is None:
            app_name = get_app_name(cls)
        basename = prefix
        patterns = []

        for view, pattern in cls._meta.view_patterns.items():
            if basename:
                prefix = '%s-%s' % (basename, cls._meta.view_url_names[view])
            else:
                prefix = cls._meta.view_url_names[view]
            view_func = cls.as_view(view, **(initkwargs or {}))
            pattern = url(pattern, view_func, name=prefix)
            patterns.append(pattern)

        return patterns

    def init(self, request, *args, **kwargs):
        """
        This method is called to initialize the class-based view with arguments
        passed to the view function before dispatching to the child view.

        The default implementation simply saves each value in the corresponding
        `request`, `args` and `kwargs` attributes.
        """

        self.request = request
        self.args = args
        self.kwargs = kwargs

    def init_child(self, view):
        """
        This method is executed every time a new sub-view view instance is
        created.

        The default implementation simply saves itself in the `parent`
        attribute and saves copy the `request`, `args`, and `kwargs` attributes.
        """

        view.parent = self
        view.request = self.request
        view.args = self.args
        view.kwargs = self.kwargs

    def dispatch(self, request, *args, **kwargs):
        """
        Instantiate each children class and return the first that accepts the
        request.
        """

        self.init(request, *args, **kwargs)

        if self.dispatch_to is not None:
            return self.dispatch_to_child(self.dispatch_to, request)

        raise ImproperlyConfigured(
            'Class must be initialized with the dispatch_to attribute set.')

    def dispatch_to_child(self, view_name, request):
        """
        Dispatch url to the given child view.
        """

        try:
            attr = self._meta.view_attributes[view_name]
        except KeyError:
            raise ValueError('view %r does not exist' % view_name)

        method = getattr(self, attr)
        self.child_view_name = view_name
        return method(request, *self.args, **self.kwargs)
示例#17
0
class ModelFormMixin(FormMixin, SingleObjectMixin, edit.ModelFormMixin):
    """
    A mixin that provides a way to show and handle a modelform in a request.
    """

    fields = delegate_to_parent('fields')
示例#18
0
class CRUDViewPack(SingleObjectPackMixin, TemplateResponsePackMixin, ViewPack):
    """
    A view group that defines a CRUD interface to a model.

    It handles the following urls::

        /               --> list view
        new/            --> creates a new object
        <pk>/           --> detail view
        <pk>/edit/      --> edit object
        <pk>/delete/    --> delete object


    Each one of these entry points is controlled by a specific View inner class:

        * :class:`viewgoups.CRUDViewPack.ListView`: index listings
        * :class:`viewgoups.CRUDViewPack.CreateView`: create new objects
        * :class:`viewgoups.CRUDViewPack.DetailView`: show object's detail
        * :class:`viewgoups.CRUDViewPack.EditView`: edit object.
        * :class:`viewgoups.CRUDViewPack.DeleteView`: delete an object.

    It is possible to disable any view by setting the corresponding attribute to
    None in a subclass. One can completely replace theses view classes by their
    own views or, more conveniently, implement mixin classes that are
    automatically used during class creation::


        class MyCRUD(CRUDViewPack):
            model = MyModel

            # Disable list views
            ListView = None

            # Mixin class that is mixed with the default CreateView class
            class CreateViewMixin:
                pattern = r'^create/$'

    """
    CRUD_VIEWS = {'create', 'detail', 'update', 'delete', 'list'}

    #: List of fields that should be excluded from the model forms automatically
    #: generated in the child views. Can be used as an alternative to the
    # `fields` attribute in order to create a blacklist.
    exclude_fields = delegate_to_parent('exclude_fields', None)

    @lazy
    def fields(self):
        """Define a list of fields that are used to automatically create forms
        in the update and create views."""

        if self.exclude_fields is None:
            return forms.fields_for_model(self.model)
        else:
            exclude = self.exclude_fields
            return forms.fields_for_model(self.model, exclude=exclude)

    #: If True, the generic crud templates are not included in the list of
    #: template for child views.
    disable_crud_templates = delegate_to_parent('disable_crud_templates',
                                                False)

    #: If True (default), if will use the functions in
    # :mod:`viewpack.permissions` to check if the user has permissions to view,
    # edit or create new objects.
    check_permissions = delegate_to_parent('check_permissions', False)

    def get_template_names(self, view_name):
        assert isinstance(view_name, str), 'invalid view name: %r' % view_name

        try:
            names = super().get_template_names(view_name)
        except ImproperlyConfigured:
            if ((not self.disable_crud_templates)
                    or (view_name not in self.CRUD_VIEWS)):
                raise
            names = []

        # We add the default views to the search list of valid views
        if not self.disable_crud_templates and view_name in self.CRUD_VIEWS:
            names.append('viewpack/crud/%s%s' %
                         (view_name, self.template_extension_normalized))
            names.append('viewpack/crud/%s-base%s' %
                         (view_name, self.template_extension_normalized))
        return names

    class CreateView(VerboseNamesContextMixin, HasUploadMixin, CreateView):
        """Create new objects."""

        pattern = r'^new/$'

    class DetailView(DetailObjectContextMixin, VerboseNamesContextMixin,
                     DetailView):
        """Detail view for object."""

        pattern = r'(?P<pk>\d+)/$'

    class UpdateView(DetailObjectContextMixin, VerboseNamesContextMixin,
                     UpdateView):
        """Edit object."""

        pattern = r'^(?P<pk>\d+)/edit/$'
        success_url = '../'

    class DeleteView(DetailObjectContextMixin, VerboseNamesContextMixin,
                     DeleteView):
        """Delete object."""

        pattern = r'^(?P<pk>\d+)/delete/$'

    class ListView(VerboseNamesContextMixin, ListView):
        """List instances of the given model."""

        pattern = r'^$'
示例#19
0
class DetailWithResponseView(FormMixin, DetailView):
    """
    A detail view that creates a form to fill up a response object that
    represents the user interaction with that object in the detail view.

    One example is the user response to a quiz in the page that shows the quiz
    details.
    """

    response_form_class = delegate_to_parent('response_form_class')
    response_form_model = delegate_to_parent('response_form_model')
    response_fields = delegate_to_parent('response_fields')

    def post(self, request, *args, **kwargs):
        """
        Executed when response form is submitted.
        """

        form = self.get_form()
        if form.is_valid():
            self.response = self.get_response(form)
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

    def get_form_class(self):
        """
        Return the form class for the response object to use in this view.
        """

        if self.response_model is not None and self.response_form_class:
            raise ImproperlyConfigured(
                "Specifying both 'response_model' and 'response_form_class' "
                "is not permitted.")
        if self.response_form_class:
            return self.response_form_class
        else:
            if not (self.response_model and self.response_fields):
                raise ImproperlyConfigured(
                    "Using DetailWithResponseView without the "
                    "'response_fields' and 'response_model' attributes is "
                    "prohibited.")

            model = self.response_model
            fields = self.response_fields
            return modelform_factory(model, fields=fields)

    def get_form_kwargs(self):
        kwargs = super().get_form_kwargs()
        if hasattr(self, 'response'):
            kwargs.update({'instance': self.response})
        return kwargs

    def get_context_data(self, **kwargs):
        if 'response' not in kwargs:
            kwargs['response'] = getattr(self, 'response', None)
        return super().get_context_data(**kwargs)

    def get_response(self, form):
        """
        Create a response object from the given model form.

        This method is called after the form is validated. The default
        implementation simply calls the save() method of the ModelForm. It can
        be overridden in order to save or additional fields.
        """

        return form.save()
示例#20
0
class HasUploadMixin:
    """Adds support for upload an serialized version of object from the create
    view. Respond to multi-part POST requests and import the uploaded file into
    a new object.

    Context attributes:
        upload_enable:
            Enable upload functionality.
        upload_form:
            A form instance for the upload form.
        upload_ask:
            True if needs to ask for upload, False otherwise (for displaying
            success/failure messages).
        upload_error:
            A message with the upload error, if it exists.
    """

    #: Enable the upload functionality (default True)
    upload_enable = delegate_to_parent('upload_enable', True)

    #: Default upload form class
    upload_form_class = UploadForm

    #: The exception class raised on import errors
    import_object_exception = delegate_to_parent('import_object_exception',
                                                 SyntaxError)

    #: The url to redirect upon success. It accepts the format syntax in which
    #: is called with a dictionary with {'object': imported_object}
    upload_success_url = delegate_to_parent('upload_success_url')

    def get_context_data(self, **kwargs):
        if self.upload_enable:
            return super().get_context_data(
                upload_form=self.get_upload_form(),
                upload_ask=getattr(self, 'upload_ask', True),
                upload_error=getattr(self, 'upload_error', None),
                upload_enable=True,
                **kwargs)
        else:
            return super().get_context_data(upload_enable=False, **kwargs)

    def get_upload_form(self, *args, **kwargs):
        """Return a Form instance representing an upload form."""

        cls = self.get_upload_form_class()
        return cls(*args, **kwargs)

    def get_upload_form_class(self):
        """Return the Form subclass used from upload forms."""

        return self.upload_form_class

    def post(self, request, *args, **kwargs):
        if self.upload_enable and request.FILES:
            form = self.get_upload_form(request.POST, request.FILES)
            if form.is_valid():
                try:
                    self.object = self.get_object_from_files(request.FILES)
                except self.import_object_exception as ex:
                    self.upload_error = str(ex) or 'import error'
                    return self.upload_failure(request, *args, **kwargs)
                else:
                    return self.upload_success(request, *args, **kwargs)
        return super().post(request, *args, **kwargs)

    def upload_success(self, request, *args, **kwargs):
        """Called when import is successful."""

        if self.upload_success_url is None:
            if hasattr(self.object, 'get_absolute_url'):
                url = self.object.get_absolute_url()
            else:
                raise ImproperlyConfigured(
                    'You must either override the upload_success() method or '
                    'define a `upload_success_url` attribute.')
        else:
            url = self.upload_success_url.format(object=self.object)
        return redirect(url)

    def upload_failure(self, request, *args, **kwargs):
        """Called when import failed."""

        self.upload_ask = False
        return self.get(request, *args, **kwargs)

    def get_object_from_files(self, files):
        """Return object from the dictionary of files uploaded by the user.

        By default it expects a dictionary with a single 'file' key. This
        function reads this file and calls the `get_object_from_data()` method.
        """

        data = files['file'].read()
        obj = self.get_object_from_data(data)
        set_owner = getattr(self.parent, 'set_owner', lambda x, u: None)
        set_owner(obj, self.request.user)
        return obj

    def get_object_from_data(self, data):
        """Returns a new instance from data sent by the user.

        Object is always saved on the database."""

        obj = self.model.from_data(data)
        if obj.pk is None:
            obj.save()
        return obj
示例#21
0
class InheritanceCRUDViewPack(CRUDViewPack,
                              metaclass=InheritanceCRUDViewPackMeta):
    """Similar to ViewPack, but it dispatch to different sub-cruds depending
     on the type of the requested object.

     Each sub-crud class might define a subclass_view_name attribute that is
     used to map each subclass with the corresponding name in the
     ``/new/<subclass_view_name>`` urls.
     """

    #: Type used for dispatch.
    subclass_view_type = delegate_to_parent('subclass_view_type')

    #: A dictionary mapping each model to their respective view pack
    #: class.
    registry = None

    DetailViewMixin = DispatchViewMixin
    UpdateViewMixin = DispatchViewMixin
    DeleteViewMixin = DispatchViewMixin

    class CreateView(VerboseNamesContextMixin, TemplateView):
        """
        Creates a new instances.

        This view require a second parameter that is matched to the
        `subclass_view_type` attribute of a registered child view. The default
        implementation uses urls such as::

            new/<subclass_view_name>/

        in order to delegate to the 'create' subview of the CRUDViewPack
        associated with the given <subclass_view_name> value.
        """

        pattern = r'^new/(?P<subclass_view_name>\w*)/?$'

        def get_context_data(self, **kwargs):
            def get_name(x):
                try:
                    return getattr(x, 'subclass_view_name')
                except:
                    return x.model.__name__.lower()

            L = self.parent.get_subpack_list()
            L = [(get_name(x), x) for x in L]
            return super().get_context_data(name_view_list=L, **kwargs)

        def dispatch(self, request, *args, subclass_view_name=None, **kwargs):
            if not subclass_view_name:
                self.view_name = 'create-list'
                return super().dispatch(request, *args, **kwargs)

            view = self.get_subclass_view(subclass_view_name)
            return view.dispatch(request, *args, **kwargs)

        def get_subclass_view(self, subclass_view_name):
            """Return the child CRUDViewPack instance associated with the
            given child_view_name."""

            return self.parent.get_pack(subclass_view_name)

    # class ExtraActionView(SingleObjectMixin, View):
    #     """Captures any other sub-url and try to dispatch to some registered
    #     class."""
    #
    #     pattern = r'^(?P<pk>\d+)/(?P<url>.*)$'
    #
    #     def match_url(self, pack, url):
    #         """Searches all subviews for a matching url."""
    #
    #     def dispatch(self, request, pk, url):
    #         self.object = self.get_object()
    #         pack = self.get_pack(type(self.object))
    #         subview = self.match_url(pack, url)
    #         return self.process_subview(subvview)

    def init_subclass_view(self, cls):
        """Initialize an instance of a child view pack class."""

        return cls(dispatch_to=self.dispatch_to,
                   initkwargs=self.initkwargs,
                   parent=self,
                   request=self.request,
                   args=self.args,
                   kwargs=self.kwargs,
                   **(self.initkwargs or {}))

    def get_pack(self, value):
        """Return the child CRUDViewPack instance associated with the
        given name or type."""

        # This function accepts either a string with the pack name or a type
        if isinstance(value, str):
            for child_cls in self.registry.values():
                name = getattr(child_cls, 'subclass_view_name', None)
                if isinstance(name, str):
                    if name == value:
                        return self.init_subclass_view(child_cls)
                    continue
                child = self.init_subclass_view(child_cls)

                # If subclass_view_name is not defined, we compute it from the
                # lowercase version of the model name.
                if name is None:
                    name = child.model.__name__.lower()
                if name == value:
                    return child
            raise ValueError('invalid subclass_view_name: %r' % value)

        # Search by type
        #for child_cls in self.

    def get_subpack_list(self):
        """
        Return a list with all registered subclass views objects.

        Each view is initialized as if it would have been if executed with the
        dispatch method.
        """

        L = []
        for child_cls in self.registry.values():
            child = self.init_subclass_view(child_cls)
            L.append(child)
        return L

    def get_subpack_models(self):
        """
        Return a list with all (subclass_view_name, model) items.
        """
        return [(pack.subclass_view_name, model)
                for (model, pack) in self.registry.items()]

    @classmethod
    def register(cls,
                 viewpack=None,
                 *,
                 model=None,
                 as_fallback=False,
                 force=False):
        """
        Register the given viewgroup for objects of the given type.

        Can be used as a decorator.

        Args:
            viewpack:
                Registered class
            model:
                Optional model type associated to the group. If not givem
                it uses viewgroup.model.
            as_fallback:
                If true, register viewgroup as the fallback view for objects of
                non-registered types.
            force:
                Forces registration of an existing type.
        """

        # Decorator form
        if viewpack is None:
            return lambda viewpack: cls.register(
                viewpack, model=model, as_fallback=as_fallback, force=force)

        # Retrieves model from view, if necessary
        if as_fallback:
            model = None
        elif model is None:
            model = viewpack.model

        # Register
        if force and model in cls.registry:
            if model is None:
                raise ImproperlyConfigured(
                    'Fallback view is already registered')
            raise ImproperlyConfigured(
                'A view is already registered for model: %s' % model.__name__)
        cls.registry[model] = viewpack

        return viewpack

    def get_queryset(self):
        """
        Returns the queryset.

        If manager has a select_subclasses() method (as in Django model util's
        InheritanceManager), it uses this method.
        """

        queryset = super().get_queryset()
        if hasattr(queryset, 'select_subclasses'):
            return queryset.select_subclasses()
        return queryset

    def dispatch_to_object(self, object, request, *args, **kwargs):
        """
        Dispatch to the sub-view that is responsible for dealing with input
        object.
        """

        cls = type(object)
        try:
            view_cls = self.registry[cls]
        except KeyError:
            if None in self.registry:
                view_cls = self.registry[None]
            raise http.Http404('No view registered to %s objects' %
                               cls.__name__)

        # We now create a view object and dispatch to it
        self.subclass_view_type = cls
        self.child_view_object = view_cls(parent=self,
                                          object=object,
                                          dispatch_to=self.child_view_name)
        return self.child_view_object.dispatch(request, *args, **kwargs)