PROJECTS NOTES HOME

Dynamically generate a menu with links in django templates with context processors

1 A solution

Imagine going to base.html and writing all the a href links yourself… and if new urls appears – you go and add them to base.html..

We know better…

Let's use context processors for this task.

First I was trying to add url info into some kind of view, but ofc circular import error, because I am trying To import views from urls and urls from views.

Tried using util functions.. Nope.

Finally found out about context processors. With them you can pass ANY kind of data to EACH template.

So for exmaple, createa context_processor.py file. This can be the content:

from datetime import datetime
from one.urls import urlpatterns

def current_time(request):
    return {'current_time': datetime.now()}

def get_urls(request):
    # print(type(urlpatterns))
    # print(urlpatterns)
    return {'url_patterns': urlpatterns}

In settings.py/templates array add this - 'context_processors.get_urls',

Then in templates can loop over them:

<ul>
    {% for url in url_patterns %}
    <li><a href="{% url url.name %}">{{url.name}}</a></li>
    {% endfor %}
</ul>

Now the nav should be generated.

2 A bug in the solution and a fix for it

PROBLEM ARISES WHEN HAVING DETAIL VIEWS OF THINGS:

path('detail/<int:pk>/', OneDetailView.as_view(), name='one_detail'),

Such error:

django.urls.exceptions.NoReverseMatch: Reverse for 'one_detail' with no arguments not found. 1 pattern(s) tried: ['one/detail/(?P<pk>[0-9]+)/\\Z']

Basically it does not know what to write in url.name, since pk is not provided

{% for url in url_patterns %}
<li><a href="{% url url.name %}">{{url.name}}</a></li>
{% endfor %}

Ok you can actually fix it like this:

randompatterns = [
    # function views
    path("", views.index, name="index"),
    path("function_view", views.function_view, name="function_view"),
    # class based views
    path("class_view/", ClassView.as_view(), name="class_view"),
    path("greeting_parent/", GreetingView.as_view(), name="greeting_parent"),
    path("greeting_child/", MorningGreetingView.as_view(), name="greeting_child"),
    path("greeting_hack/", GreetingView.as_view(greeting="G'day"), name="greeting_hack"),
    path("async/", AsyncView.as_view(), name="async"),

listpatterns = [
    path("one_list_view/", OneListView.as_view(), name="one_list_view"),
]

detailpatterns = [
    path('detail/<int:pk>/', OneDetailView.as_view(), name='one_detail'),
]

urlpatterns = randompatterns + listpatterns + detailpatterns

And then:

def get_urls(request):
    # print(type(urlpatterns))
    # print(urlpatterns)
    return {'url_patterns': randompatterns + listpatterns}