Why `view_permission` and `view_or_change_permission` ?

Looking at django/django/contrib/admin/options.py I see has_view_permission and has_view_or_change_permission. Only the former is mentioned in the docs.

What confuses me is, that they both seem to do the same thing, which is return True, if the given request user has permission to view or change the given Django model instance, regardless of what the comment says in the former.

    def has_view_permission(self, request, obj=None):
        """
        Return True if the given request has permission to view the given
        Django model instance. The default implementation doesn't examine the
        `obj` parameter.

        If overridden by the user in subclasses, it should return True if the
        given request has permission to view the `obj` model instance. If `obj`
        is None, it should return True if the request has permission to view
        any object of the given type.
        """
        opts = self.opts
        codename_view = get_permission_codename("view", opts)
        codename_change = get_permission_codename("change", opts)
        return request.user.has_perm(
            "%s.%s" % (opts.app_label, codename_view)
        ) or request.user.has_perm("%s.%s" % (opts.app_label, codename_change))

    def has_view_or_change_permission(self, request, obj=None):
        return self.has_view_permission(request, obj) or self.has_change_permission(
            request, obj
        )

I guess they both exist to have a way to override them individually? And the default for has_view_permission should be has_view_or_change_permission? In that case I would have at least expected has_view_or_change_permission to have the implementation of what has_view_permission has now and has_view_permission just using has_view_or_change_permission. But maybe I’m missing something here?

Or is it that the permission to view an object is given, when the user has either a view or change permission?

Oh just came here after reading your post in my email client. Why did you delete it? I want to know how the mystery is solved!

Honestly, I got too frustrated looking at it and decided not to go down that rabbit hole any further.

But as I said I think it is that way, mainly to be able to override the has_xyz_permission methods like RowLevelChangePermissionModelAdmin does for tests.

Fair enough. IMO looks like has_view_or_change_permission is intended for internal use only, as a shortcut for calling both methods when applicable. That’s why it’s not documented, the way to override permissions is only to override the specific change, delete, or view method .