Description
Took me a bit, but I can create menus alright. Cannot for the life of me figure out how to dynamically allocate URLs to each of the menus/submenus. I have a list of cancerTypes
that I have in the Django database. I am trying to use those to generate a series of sub-menus, one for each cancerType
. I can create the menu entries but not link them to a page with a URL using reverse()
.
My menus.py looks like this:
from django.urls import reverse
from simple_menu import Menu, MenuItem
from hc.models import CancerType
from hc.views import CancerView, SampleView
level1Cancertypes = CancerType.objects.filter(parent__name="ZERO2")
level1 = []
for cancer_type in level1Cancertypes:
menu_item = MenuItem(
title=cancer_type.name, # Use the name of the CancerType as the title of the menu item
url=reverse("hc:cancer")
)
level1.append(menu_item)
Menu.add_item("main", MenuItem(title="All",
url=reverse("hc:cancer"),
weight=10,
children=level1
))
Menu.add_item("main", MenuItem(title="Sample",
url=reverse("hc:sample"),
# url="/wibble",
weight=10,
))
my urls.py looks like this:
from django.urls import path
from . import views
app_name = "hc"
urlpatterns = [
path("", views.IndexView.as_view(), name="index"),
path('cancer/', views.CancerView.as_view(), name="cancer"),
path("sample/", views.SampleView.as_view(), name="sample"),
]
And the relevant part of my views.py looks like this:
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from django.views.generic import ListView, TemplateView
from .models import CancerType, Sample
class IndexView(generic.ListView):
template_name = "hc/index.html"
class CancerView(TemplateView):
template_name = 'hc/cancer.html'
class SampleView(TemplateView):
template_name = 'hc/sample.html'
All of this I've tried to make as identical as possible to the code in the example4 here — urls.py, views.py and menus.py. This all works.
As soon as I try to pass an argument via kwargs, it falls over. Line 23 of menus.py suggests that I should be able to do something like this in my menus.py:
for cancer_type in level1Cancertypes:
menu_item = MenuItem(
title=cancer_type.name,
url=reverse("hc:cancer", kwargs={'cancerId': 1})
)
as long as I change the url pattern to be:
urlpatterns = [
path("", views.IndexView.as_view(), name="index"),
path('cancer/<int:cancerId>', views.CancerView.as_view(), name="cancer"),
path("sample/", views.SampleView.as_view(), name="sample"),
]
The instant I do that, though, the app goes down with
Reverse for 'cancer' with no arguments not found. 1 pattern(s) tried: ['hc/cancer/(?P<cancerId>[0-9]+)\\Z']
There's nothing in the example views.py to suggest that I should be changing the number of parameters the view needs.
class SubPageView(TemplateView):
template_name = 'accounts/subpage.html'
And if I manually enter the URL http://127.0.0.1:8000/hc/cancer/1/
, I get a 404. I have checked, there is a cancer type with an id of 1.
Issues #70 and (possibly?) #83 might be suggesting that the reverse
call in the menu item creation might be a problem due to being resolved too early or some such? Not sure if I'm following those right. Either way, the subclassing solution in #70 doesn't appear to work for me. Takes me right back to
django.urls.exceptions.NoReverseMatch: Reverse for 'cancer' not found. 'cancer' is not a valid view function or pattern name.
which is exceptionally frustrating when best I can tell from the Django documentation, using "name" in
path('cancer/<int:pk>', views.CancerView.as_view(), name="cancer")
should be sufficient to define a view called "cancer". In short, I have no idea what's happening there (day 2 of Django for me, which might have something to do with it)
Anyway. Any thoughts on what I'm doing would be much appreciated.
Thanks
Ben.