django/django · warning · Http404

Model %(model_name)r not found in app %(app_label)r

Error message

Model %(model_name)r not found in app %(app_label)r

What it means

Raised as Http404 by admindocs ModelDetailView when the app was found but app_config.get_model(model_name) raises LookupError, meaning no model with that name lives in the app. The model detail route resolves app then model, so a bad model_name yields a 404.

Source

Thrown at django/contrib/admindocs/views.py:238

            if user_has_model_view_permission(self.request.user, m._meta)
        ]
        return super().get_context_data(**{**kwargs, "models": m_list})


class ModelDetailView(BaseAdminDocsView):
    template_name = "admin_doc/model_detail.html"

    def get_context_data(self, **kwargs):
        model_name = self.kwargs["model_name"]
        # Get the model class.
        try:
            app_config = apps.get_app_config(self.kwargs["app_label"])
        except LookupError:
            raise Http404(_("App %(app_label)r not found") % self.kwargs)
        try:
            model = app_config.get_model(model_name)
        except LookupError:
            raise Http404(
                _("Model %(model_name)r not found in app %(app_label)r") % self.kwargs
            )

        opts = model._meta
        if not user_has_model_view_permission(self.request.user, opts):
            raise PermissionDenied

        title, body, metadata = utils.parse_docstring(model.__doc__)
        title = title and utils.parse_rst(title, "model", _("model:") + model_name)
        body = body and utils.parse_rst(body, "model", _("model:") + model_name)

        # Gather fields/field descriptions.
        fields = []
        for field in opts.fields:
            # ForeignKey is a special case since the field will actually be a
            # descriptor that returns the other object
            if isinstance(field, models.ForeignKey):
                data_type = field.remote_field.model.__name__

View on GitHub (pinned to ae25a40be0)

Solutions

  1. Use the exact model class name (case-sensitive) as it appears in the app's models module.
  2. Confirm the model still exists in that app's codebase.
  3. Fix or remove bookmarks/links referencing the old model name.

Example fix

// before: wrong casing / name
/admin/docs/models/auth.userprofile/
  (actual class is UserProfile, or model lives in a different app)

// after: exact class name in the correct app
/admin/docs/models/accounts.UserProfile/
Defensive patterns

Strategy: validation

Validate before calling

# Verify the model exists in the app before building the doc URL.
from django.apps import apps

def model_doc_url(app_label, model_name):
    try:
        cfg = apps.get_app_config(app_label)
    except LookupError:
        return None
    if model_name not in {m.__name__ for m in cfg.get_models()}:
        return None
    return f"/admin/docs/models/{app_label}.{model_name}/"

Try / catch

from django.http import Http404

try:
    return model_detail_view(request, app_label, model_name)
except Http404:
    return render(request, 'docs/model_not_found.html', status=404)

Prevention

When it happens

Trigger: Visiting `/admin/docs/models/<app>.<model>/` where model_name is misspelled, uses the wrong case, or refers to a model that was deleted. Python class names are case-sensitive in the URL.

Common situations: Typos or wrong casing in the model_name segment; a model removed by a migration but still linked; confusing the model's verbose name with its class name.

Related errors


AI-assisted analysis of django/django@ae25a40be0 (2026-08-06). Data as JSON: /api/errors/4fdbc8058f6a03f0. Report an issue: GitHub.