djangodjango-viewsdjango-admindjango-urls

extending django admin by a view without a model


I have a customized admin view - my app is called virtual:

class VirtualAdminSite(admin.AdminSite):
    index_template = "virtual/admin_index.html"

    def index(self, request, extra_context=None):
        extra_context = extra_context or {}
        return super().index(request, extra_context)

    def get_urls(self):
        urls = super().get_urls()
        my_urls = path("virtual/info/", self.admin_view(self.info), name="info")
        urls.append(my_urls)
        return urls

    def info(self, request):
        return HttpResponse("hello")

and I want to be able to include the url in the newly created admin_index.html, so I did (please ignore I used HTMX to load this bc it's shorter than AJAX in vanilla JS):

{% block content %}
    <div id="content-main">
        {% include "admin/app_list.html" with app_list=app_list show_changelinks=True %}

        Info: <h3 hx-get="{% url 'info' %}" hx-trigger="load"> loading ... </h3> 
    </div>
{% endblock %}

but I get a: Reverse for 'info' not found. 'info' is not a valid view function or pattern name error. I already tried adding admin/ in the path, and deleting virtual but everything fails.

edit: When looping over all the urls before returning them:

<URLPattern '' [name='index']>
<URLPattern 'login/' [name='login']>
<URLPattern 'logout/' [name='logout']>
<URLPattern 'password_change/' [name='password_change']>
<URLPattern 'password_change/done/' [name='password_change_done']>
<URLPattern 'autocomplete/' [name='autocomplete']>
<URLPattern 'jsi18n/' [name='jsi18n']>
<URLPattern 'r/<int:content_type_id>/<path:object_id>/' [name='view_on_site']>
<URLResolver <URLPattern list> (None:None) 'virtual/product/'>
<URLResolver <URLPattern list> (None:None) 'virtual/store/'>
<URLPattern '^(?P<app_label>virtual)/$' [name='app_list']>
<URLPattern '(?P<url>.*)$'>
<URLPattern 'virtual/info/' [name='info']>

I see nothing too odd. Still I see a 404 in the network tab when trying to resolve: {% url 'admin:info' %}.


Solution

  • If I recall correctly, the .urls of a site by default pases the url patterns as well as the app_namespace which is by default admin, and the instancce namespace, which is the name of the site you attached. Indeed, in the source codeĀ [GitHub], we see:

    @property 
    def urls(self):
        return self.get_urls(), "admin", self.name

    You thus refer to the view with:

    {% url 'admin:info' %}

    Additionally, you need to provide a name for the path:

    my_urls = path('virtual/info/', self.admin_view(self.info), name='info')

    A final problem turned out to be that you added the path at the end of the list, and there is a "catch all" pattern before that, so you can insert it in front, or at least before the "catch all":

    def get_urls(self):
        urls = super().get_urls()
        my_urls = path('virtual/info/', self.admin_view(self.info), name='info')
        urls.insert(0, my_urls)
        return urls