Skip to content

GenericView

Generated view class for ViewAction.

GenericView

djadmin.factories.base.GenericView

ViewAction View class for site.None generated by ViewFactory.

Base class: django.views.generic.detail.DetailView
Mixins: PermissionMixin, DjAdminViewMixin
Active plugins: djadmin.plugins.contrib_auth, examples.webshop, djadmin_formset, djadmin_classy_doc, djadmin_filters, djadmin.plugins.permissions, djadmin.plugins.core, djadmin.plugins.theme

View Information

Action
ViewAction
ModelAdmin
djadmin.options.ModelAdmin

View Construction

Base Class

django.views.generic.detail.DetailView

Mixins

  • djadmin.plugins.permissions.mixins.PermissionMixin djadmin.plugins.permissions.djadmin_hooks
  • djadmin.plugins.core.mixins.DjAdminViewMixin djadmin.plugins.core.djadmin_hooks

Bound Methods from Action

  • get_template_names() from ViewAction
  • get_layout() from ViewAction
  • get_context_data() from ViewAction

Method Resolution Order

  1. djadmin.factories.base.GenericView
  2. djadmin.plugins.permissions.mixins.PermissionMixin djadmin.plugins.permissions.djadmin_hooks
  3. django.contrib.auth.mixins.UserPassesTestMixin
  4. django.contrib.auth.mixins.AccessMixin
  5. djadmin.plugins.core.mixins.DjAdminViewMixin djadmin.plugins.core.djadmin_hooks
  6. django.views.generic.detail.DetailView base class from ViewAction
  7. django.views.generic.detail.SingleObjectTemplateResponseMixin
  8. django.views.generic.base.TemplateResponseMixin
  9. django.views.generic.detail.BaseDetailView
  10. django.views.generic.detail.SingleObjectMixin
  11. django.views.generic.base.ContextMixin
  12. django.views.generic.base.View

Attributes

Attribute Value Defined in
action ViewAction() djadmin.factories.base.GenericView
admin_site AdminSite(name='docs_temp') djadmin.factories.base.GenericView
content_type None django.views.generic.base.TemplateResponseMixin
context_object_name None django.views.generic.detail.SingleObjectMixin
extra_context None django.views.generic.base.ContextMixin
http_method_names ['get', 'post', 'put', 'patch', 'delete', 'head', 'option... django.views.generic.base.View
login_url None django.contrib.auth.mixins.AccessMixin
model None django.views.generic.detail.SingleObjectMixin
model_admin ModelAdmin() djadmin.factories.base.GenericView
permission_denied_message django.contrib.auth.mixins.AccessMixin
pk_url_kwarg pk django.views.generic.detail.SingleObjectMixin
query_pk_and_slug False django.views.generic.detail.SingleObjectMixin
queryset None django.views.generic.detail.SingleObjectMixin
raise_exception False django.contrib.auth.mixins.AccessMixin
redirect_field_name next django.contrib.auth.mixins.AccessMixin
response_class django.template.response.TemplateResponse django.views.generic.base.TemplateResponseMixin
slug_field slug django.views.generic.detail.SingleObjectMixin
slug_url_kwarg slug django.views.generic.detail.SingleObjectMixin
template_engine None django.views.generic.base.TemplateResponseMixin
template_name None django.views.generic.base.TemplateResponseMixin
template_name_field None django.views.generic.detail.SingleObjectTemplateResponseMixin
template_name_suffix _detail django.views.generic.detail.SingleObjectTemplateResponseMixin
view_is_async False django.views.generic.base.View

Methods

__init__(self, **kwargs)

Defined in: <class 'django.views.generic.base.View'>

Constructor. Called in the URLconf; can contain helpful extra keyword arguments, and other things.

Source code in base.py line 54
    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in kwargs.items():
            setattr(self, key, value)

as_view(**initkwargs) @classmethod

Defined in: <class 'django.views.generic.base.View'>

Main entry point for a request-response process.

Source code in base.py line 81
    @classonlymethod
    def as_view(cls, **initkwargs):
        """Main entry point for a request-response process."""
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError(
                    "The method name %s is not accepted as a keyword argument "
                    "to %s()." % (key, cls.__name__)
                )
            if not hasattr(cls, key):
                raise TypeError(
                    "%s() received an invalid keyword %r. as_view "
                    "only accepts arguments that are already "
                    "attributes of the class." % (cls.__name__, key)
                )

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            self.setup(request, *args, **kwargs)
            if not hasattr(self, "request"):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)

        view.view_class = cls
        view.view_initkwargs = initkwargs

        # __name__ and __qualname__ are intentionally left unchanged as
        # view_class should be used to robustly determine the name of the view
        # instead.
        view.__doc__ = cls.__doc__
        view.__module__ = cls.__module__
        view.__annotations__ = cls.dispatch.__annotations__
        # Copy possible attributes set by decorators, e.g. @csrf_exempt, from
        # the dispatch method.
        view.__dict__.update(cls.dispatch.__dict__)

        # Mark the callback if the view class is async.
        if cls.view_is_async:
            markcoroutinefunction(view)

        return view

build_form(self, form=None)

Defined in: <class 'djadmin.plugins.core.mixins.DjAdminViewMixin'>

Build form class from layout or fields. Override in plugins to customize.

This method is called by get_form_class() when no explicit form_class is provided. The default implementation uses FormBuilder to create forms from layouts or fields.

Returns: ModelForm class ready for instantiation

Source code in mixins.py line 246
    def build_form(self, form=None):
        """
        Build form class from layout or fields. Override in plugins to customize.

        This method is called by get_form_class() when no explicit form_class is provided.
        The default implementation uses FormBuilder to create forms from layouts or fields.

        Returns:
            ModelForm class ready for instantiation
        """
        layout = self.get_layout()

        if layout:
            # Build from layout using FormBuilder
            print('using FormBuilder.from_layout')
            return FormBuilder.from_layout(layout, self.model, form_class=None)

        print('using FormBuilder.create_form')
        # No layout - build from fields

        fields = getattr(self, 'get_fields', lambda: '__all__')()
        return FormBuilder.create_form(self.model, fields=fields)

dispatch(self, request, *args, **kwargs)

Defined in: <class 'django.views.generic.base.View'>

Source code in base.py line 134
    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        if request.method.lower() in self.http_method_names:
            handler = getattr(
                self, request.method.lower(), self.http_method_not_allowed
            )
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)
Source code in mixins.py line 131
    def dispatch(self, request, *args, **kwargs):
        user_test_result = self.get_test_func()()
        if not user_test_result:
            return self.handle_no_permission()
        return super().dispatch(request, *args, **kwargs)

filtered_actions

Defined in: <class 'djadmin.plugins.core.mixins.DjAdminViewMixin'>

Filtered action lists by user permissions, cached on view instance.

For object-based views (UpdateView, DetailView, DeleteView), filters actions based on the specific object. For list views, filters at model level.

Results are cached on the view instance, which is per-request since Django creates a new view instance for each request. Combined with request-level caching in ModelAdmin.filter_actions(), this ensures actions are filtered only once per request.

Performance Impact: Without caching: Actions filtered multiple times per request With caching: Actions filtered once per request (view instance)

Returns: dict: Dictionary with filtered action lists: - filtered_general_actions - filtered_bulk_actions - filtered_record_actions

get(self, request, *args, **kwargs)

Defined in: <class 'django.views.generic.detail.BaseDetailView'>

Source code in detail.py line 111
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        context = self.get_context_data(object=self.object)
        return self.render_to_response(context)

get_context_data(self, **kwargs)

Defined in: <class 'django.views.generic.base.ContextMixin'>

Source code in actions.py line 332
    def get_context_data(self, **kwargs):
        """
        Add layout_items to context for template rendering.

        Returns:
            Context dict with layout_items
        """
        context = super().get_context_data(**kwargs)

        # Get layout
        layout = self.get_layout()

        if layout:
            # Render layout for display
            obj = self.get_object()
            layout_items = layout.render_for_display(obj)
            context['layout_items'] = layout_items

        return context
Source code in detail.py line 92
    def get_context_data(self, **kwargs):
        """Insert the single object into the context dict."""
        context = {}
        if self.object:
            context["object"] = self.object
            context_object_name = self.get_context_object_name(self.object)
            if context_object_name:
                context[context_object_name] = self.object
        context.update(kwargs)
        return super().get_context_data(**context)
Source code in mixins.py line 126
    def get_context_data(self, **kwargs):
        """
        Add standard admin context to all views.

        When bound to the view, self is the view instance which has:
        - self.action: Action instance
        - self.model: Model class
        - self.model_admin: ModelAdmin instance
        - self.admin_site: AdminSite instance
        - self.request: Current request
        """
        from djadmin.plugins import pm

        # Call super to get base context from Django CBV
        context = super().get_context_data(**kwargs)

        # Add request to context (needed for inclusion tags)
        context['request'] = self.request

        # Add standard admin context
        context['model'] = self.model
        context['opts'] = self.model._meta if self.model else None
        context['action'] = self.action
        context['model_admin'] = self.model_admin
        context['admin_site'] = self.admin_site

        # Add version information
        context['djadmin_version'] = djadmin.__version__
        context['django_version'] = django.get_version()

        # Add site-wide URLs
        try:
            context['index_url'] = reverse(f'{self.admin_site.name}:index')
        except Exception:
            context['index_url'] = '/'

        # Add site configuration
        context['site_header'] = self.admin_site.site_header
        context['site_title'] = self.admin_site.site_title
        context['index_title'] = self.admin_site.index_title

        # Add list URL (using admin_site namespace)
        # Skip for site-level actions (model=None)
        if self.model is not None:
            list_url_name = f'{self.model_admin.list_url_name}'
            context['list_url'] = self.admin_site.reverse(list_url_name)
        else:
            context['list_url'] = context.get('index_url', '/')

        # Add namespaced URL names for actions
        namespace = self.admin_site.name
        context['action_namespace'] = namespace

        # Add breadcrumbs
        context['breadcrumb_list'] = self._get_breadcrumbs()

        # Add assets from plugins
        assets = self._get_assets_from_plugins()
        context['assets'] = assets

        # Add sidebar widgets for template rendering
        sidebar_widgets = self._get_sidebar_widgets_for_template()
        context['sidebar_widgets'] = sidebar_widgets

        # Add column header icons for list views
        column_header_icons = self._get_column_header_icons()
        context['column_header_icons'] = column_header_icons

        # Add filtered actions to context (permission-checked)
        # This ensures all views (ListView, UpdateView, CreateView, etc.) get filtered actions
        if self.model is not None and self.model_admin is not None:
            # Add unfiltered action lists (for template tag use in ListView)
            context['general_actions'] = self.model_admin.general_actions
            context['bulk_actions'] = self.model_admin.bulk_actions
            context['record_actions'] = self.model_admin.record_actions

            # Add filtered action lists (for use in templates)
            context.update(self.filtered_actions)

        # Allow plugins to add more context
        plugin_contexts = pm.hook.djadmin_add_context_data(
            context=context,
            request=self.request,
            view=self,
        )

        for plugin_context in plugin_contexts:
            if plugin_context:
                context.update(plugin_context)

        if settings.DEBUG:
            # List loaded plugins for debugging
            # djp.PluginManager wraps pluggy, access the underlying manager
            try:
                # Get plugins from the underlying pluggy manager
                if hasattr(pm, '_pm'):
                    # djp stores the pluggy manager as _pm
                    plugins = pm._pm.get_plugins()
                elif hasattr(pm, 'get_plugins'):
                    plugins = pm.get_plugins()
                else:
                    # Fallback: just note that we couldn't list plugins
                    plugins = ['(plugin listing not available)']

                context['debug_loaded_plugins'] = [str(plugin) for plugin in plugins]
            except Exception as e:
                context['debug_loaded_plugins'] = [f'Error listing plugins: {e}']

            # Debug: Show view's MRO (Method Resolution Order) to see which mixins are applied
            context['debug_view_mro'] = [cls.__name__ for cls in self.__class__.__mro__[:10]]

            # Debug: Show form class being used
            if hasattr(self, 'form_class'):
                context['debug_form_class'] = str(self.form_class)

            # Debug: Show action class hierarchy
            context['debug_action_mro'] = [cls.__name__ for cls in self.action.__class__.__mro__[:10]]

        return context
Source code in view_mixins.py line 332
    def get_context_data(self, **kwargs):
        """
        Add layout_items to context for template rendering.

        Returns:
            Context dict with layout_items
        """
        context = super().get_context_data(**kwargs)

        # Get layout
        layout = self.get_layout()

        if layout:
            # Render layout for display
            obj = self.get_object()
            layout_items = layout.render_for_display(obj)
            context['layout_items'] = layout_items

        return context

get_context_object_name(self, obj)

Defined in: <class 'django.views.generic.detail.SingleObjectMixin'>

Get the name to use for the object.

Source code in detail.py line 83
    def get_context_object_name(self, obj):
        """Get the name to use for the object."""
        if self.context_object_name:
            return self.context_object_name
        elif isinstance(obj, models.Model):
            return obj._meta.model_name
        else:
            return None

get_layout(self) bound from ViewAction

Defined in: <class 'djadmin.factories.base.GenericView'>

Get layout for display.

Fallback order: 1. view_layout (action-specific) 2. update_layout (shares with edit view) 3. layout (generic) 4. Auto-generate from model fields

Returns: Layout instance or None

Source code in actions.py line 281
    def get_layout(self):
        """
        Get layout for display.

        Fallback order:
        1. view_layout (action-specific)
        2. update_layout (shares with edit view)
        3. layout (generic)
        4. Auto-generate from model fields

        Returns:
            Layout instance or None
        """
        # Try view_layout first (most specific)
        layout = getattr(self.model_admin, 'view_layout', None)
        if layout:
            return layout

        # Fallback to update_layout (share with edit view)
        layout = getattr(self.model_admin, 'update_layout', None)
        if layout:
            return layout

        # Fallback to generic layout
        layout = getattr(self.model_admin, 'layout', None)
        if layout:
            return layout

        # No layout defined - auto-generate from model fields
        return None

get_login_url(self)

Defined in: <class 'django.contrib.auth.mixins.AccessMixin'>

Override this method to override the login_url attribute.

Source code in mixins.py line 21
    def get_login_url(self):
        """
        Override this method to override the login_url attribute.
        """
        login_url = self.login_url or settings.LOGIN_URL
        if not login_url:
            raise ImproperlyConfigured(
                f"{self.__class__.__name__} is missing the login_url attribute. Define "
                f"{self.__class__.__name__}.login_url, settings.LOGIN_URL, or override "
                f"{self.__class__.__name__}.get_login_url()."
            )
        return str(login_url)

get_object(self, queryset=None)

Defined in: <class 'django.views.generic.detail.SingleObjectMixin'>

Return the object the view is displaying.

Require self.queryset and a pk or slug argument in the URLconf. Subclasses can override this to return any object.

Source code in detail.py line 21
    def get_object(self, queryset=None):
        """
        Return the object the view is displaying.

        Require `self.queryset` and a `pk` or `slug` argument in the URLconf.
        Subclasses can override this to return any object.
        """
        # Use a custom queryset if provided; this is required for subclasses
        # like DateDetailView
        if queryset is None:
            queryset = self.get_queryset()

        # Next, try looking up by primary key.
        pk = self.kwargs.get(self.pk_url_kwarg)
        slug = self.kwargs.get(self.slug_url_kwarg)
        if pk is not None:
            queryset = queryset.filter(pk=pk)

        # Next, try looking up by slug.
        if slug is not None and (pk is None or self.query_pk_and_slug):
            slug_field = self.get_slug_field()
            queryset = queryset.filter(**{slug_field: slug})

        # If none of those are defined, it's an error.
        if pk is None and slug is None:
            raise AttributeError(
                "Generic detail view %s must be called with either an object "
                "pk or a slug in the URLconf." % self.__class__.__name__
            )

        try:
            # Get the single item from the filtered queryset
            obj = queryset.get()
        except queryset.model.DoesNotExist:
            raise Http404(
                _("No %(verbose_name)s found matching the query")
                % {"verbose_name": queryset.model._meta.verbose_name}
            )
        return obj
Source code in mixins.py line 39
    def get_object(self, queryset=None):
        """Override to check object permissions after fetching."""
        obj = super().get_object(queryset)

        # Get permission class from action or model_admin
        permission_class = self._get_permission_class()

        if permission_class is not None:
            # Check object permission
            if not permission_class.has_object_permission(self, obj):
                raise PermissionDenied(f'You do not have permission to access this {obj._meta.verbose_name}.')

        return obj

get_permission_denied_message(self)

Defined in: <class 'django.contrib.auth.mixins.AccessMixin'>

Override this method to override the permission_denied_message attribute.

Source code in mixins.py line 34
    def get_permission_denied_message(self):
        """
        Override this method to override the permission_denied_message attribute.
        """
        return self.permission_denied_message

get_queryset(self)

Defined in: <class 'django.views.generic.detail.SingleObjectMixin'>

Return the QuerySet that will be used to look up the object.

This method is called by the default implementation of get_object() and may not be called if get_object() is overridden.

Source code in detail.py line 61
    def get_queryset(self):
        """
        Return the `QuerySet` that will be used to look up the object.

        This method is called by the default implementation of get_object() and
        may not be called if get_object() is overridden.
        """
        if self.queryset is None:
            if self.model:
                return self.model._default_manager.all()
            else:
                raise ImproperlyConfigured(
                    "%(cls)s is missing a QuerySet. Define "
                    "%(cls)s.model, %(cls)s.queryset, or override "
                    "%(cls)s.get_queryset()." % {"cls": self.__class__.__name__}
                )
        return self.queryset.all()

get_redirect_field_name(self)

Defined in: <class 'django.contrib.auth.mixins.AccessMixin'>

Override this method to override the redirect_field_name attribute.

Source code in mixins.py line 40
    def get_redirect_field_name(self):
        """
        Override this method to override the redirect_field_name attribute.
        """
        return self.redirect_field_name

get_slug_field(self)

Defined in: <class 'django.views.generic.detail.SingleObjectMixin'>

Get the name of a slug field to be used to look up by slug.

Source code in detail.py line 79
    def get_slug_field(self):
        """Get the name of a slug field to be used to look up by slug."""
        return self.slug_field

get_template_names(self)

Defined in: <class 'django.views.generic.base.TemplateResponseMixin'>

Return a list of template names to be used for the request. Must return a list. May not be called if render_to_response() is overridden.

Source code in actions.py line 175
    def get_template_names(self):
        """
        Get template names as a list (Django CBV expects plural method).

        This wraps get_template_name() and ensures the result is a list.

        Returns:
            List of template path strings
        """
        template_names = []

        if model_name := getattr(getattr(self.model, '_meta', None), 'model_name', None):
            template_names.append(f'djadmin/{self.model._meta.app_label}/{model_name}_{self.action.action_name}.html')
        template_names.append(f'djadmin/actions/{self.action.action_name}.html')

        return template_names
Source code in detail.py line 121
    def get_template_names(self):
        """
        Return a list of template names to be used for the request. May not be
        called if render_to_response() is overridden. Return a list containing
        ``template_name``, if set on the value. Otherwise, return a list
        containing:

        * the contents of the ``template_name_field`` field on the
          object instance that the view is operating upon (if available)
        * ``<app_label>/<model_name><template_name_suffix>.html``
        """
        try:
            names = super().get_template_names()
        except ImproperlyConfigured:
            # If template_name isn't specified, it's not a problem --
            # we just start with an empty list.
            names = []

            # If self.template_name_field is set, grab the value of the field
            # of that name from the object; this is the most specific template
            # name, if given.
            if self.object and self.template_name_field:
                name = getattr(self.object, self.template_name_field, None)
                if name:
                    names.insert(0, name)

            # The least-specific option is the default <app>/<model>_detail.html;
            # only use this if the object in question is a model.
            if isinstance(self.object, models.Model):
                object_meta = self.object._meta
                names.append(
                    "%s/%s%s.html"
                    % (
                        object_meta.app_label,
                        object_meta.model_name,
                        self.template_name_suffix,
                    )
                )
            elif getattr(self, "model", None) is not None and issubclass(
                self.model, models.Model
            ):
                names.append(
                    "%s/%s%s.html"
                    % (
                        self.model._meta.app_label,
                        self.model._meta.model_name,
                        self.template_name_suffix,
                    )
                )

            # If we still haven't managed to find any template names, we should
            # re-raise the ImproperlyConfigured to alert the user.
            if not names:
                raise ImproperlyConfigured(
                    "SingleObjectTemplateResponseMixin requires a definition "
                    "of 'template_name', 'template_name_field', or 'model'; "
                    "or an implementation of 'get_template_names()'."
                )

        return names
Source code in base.py line 175
    def get_template_names(self):
        """
        Get template names as a list (Django CBV expects plural method).

        This wraps get_template_name() and ensures the result is a list.

        Returns:
            List of template path strings
        """
        template_names = []

        if model_name := getattr(getattr(self.model, '_meta', None), 'model_name', None):
            template_names.append(f'djadmin/{self.model._meta.app_label}/{model_name}_{self.action.action_name}.html')
        template_names.append(f'djadmin/actions/{self.action.action_name}.html')

        return template_names

get_test_func(self)

Defined in: <class 'django.contrib.auth.mixins.UserPassesTestMixin'>

Override this method to use a different test_func method.

Source code in mixins.py line 125
    def get_test_func(self):
        """
        Override this method to use a different test_func method.
        """
        return self.test_func

handle_no_permission(self)

Defined in: <class 'django.contrib.auth.mixins.AccessMixin'>

Source code in mixins.py line 46
    def handle_no_permission(self):
        if self.raise_exception or self.request.user.is_authenticated:
            raise PermissionDenied(self.get_permission_denied_message())

        path = self.request.build_absolute_uri()
        resolved_login_url = resolve_url(self.get_login_url())
        # If the login url is the same scheme and net location then use the
        # path as the "next" url.
        login_scheme, login_netloc = urlsplit(resolved_login_url)[:2]
        current_scheme, current_netloc = urlsplit(path)[:2]
        if (not login_scheme or login_scheme == current_scheme) and (
            not login_netloc or login_netloc == current_netloc
        ):
            path = self.request.get_full_path()
        return redirect_to_login(
            path,
            resolved_login_url,
            self.get_redirect_field_name(),
        )

http_method_not_allowed(self, request, *args, **kwargs)

Defined in: <class 'django.views.generic.base.View'>

Source code in base.py line 146
    def http_method_not_allowed(self, request, *args, **kwargs):
        response = HttpResponseNotAllowed(self._allowed_methods())
        log_response(
            "Method Not Allowed (%s): %s",
            request.method,
            request.path,
            response=response,
            request=request,
        )

        if self.view_is_async:

            async def func():
                return response

            return func()
        else:
            return response

options(self, request, *args, **kwargs)

Defined in: <class 'django.views.generic.base.View'>

Handle responding to requests for the OPTIONS HTTP verb.

Source code in base.py line 165
    def options(self, request, *args, **kwargs):
        """Handle responding to requests for the OPTIONS HTTP verb."""
        response = HttpResponse()
        response.headers["Allow"] = ", ".join(self._allowed_methods())
        response.headers["Content-Length"] = "0"

        if self.view_is_async:

            async def func():
                return response

            return func()
        else:
            return response

render_to_response(self, context, **response_kwargs)

Defined in: <class 'django.views.generic.base.TemplateResponseMixin'>

Return a response, using the response_class for this view, with a template rendered with the given context.

Pass response_kwargs to the constructor of the response class.

Source code in base.py line 192
    def render_to_response(self, context, **response_kwargs):
        """
        Return a response, using the `response_class` for this view, with a
        template rendered with the given context.

        Pass response_kwargs to the constructor of the response class.
        """
        response_kwargs.setdefault("content_type", self.content_type)
        return self.response_class(
            request=self.request,
            template=self.get_template_names(),
            context=context,
            using=self.template_engine,
            **response_kwargs,
        )

setup(self, request, *args, **kwargs)

Defined in: <class 'django.views.generic.base.View'>

Initialize attributes shared by all view methods.

Source code in base.py line 126
    def setup(self, request, *args, **kwargs):
        """Initialize attributes shared by all view methods."""
        if hasattr(self, "get") and not hasattr(self, "head"):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs

test_func(self)

Defined in: <class 'django.contrib.auth.mixins.UserPassesTestMixin'>

Source code in mixins.py line 118
    def test_func(self):
        raise NotImplementedError(
            "{} is missing the implementation of the test_func() method.".format(
                self.__class__.__name__
            )
        )
Source code in mixins.py line 16
    def test_func(self):
        """
        Permission check method for UserPassesTestMixin.

        This method is called by UserPassesTestMixin to check if the user
        has permission to access the view.

        Returns:
            bool: True if user has permission, False otherwise
        """
        # Get permission from action or model_admin
        perm = self._get_permission_class()

        if perm is None:
            # None means no permission enforcement (allow all access)
            # This happens when:
            # 1. Explicitly set to None on ModelAdmin or Action
            # 2. No model_admin exists (site-level views like DashboardAction)
            return True

        # Execute permission with view (self is the view)
        return perm(self)

Fields

Field Type Related To
__dict__ getset_descriptor -
__weakref__ getset_descriptor -