Context variables not being passed to template in Django class-based view
Question:
Banging my head against a wall.. I’m trying to return a table of Job objects, with views separated by month. I’m passing ‘year’ and ‘month’ variables through get_context_data, yet in my template they’re returning blank strings. Even ChatGPT can’t find anything wrong lol. Can anyone spot something?
Here’s my view:
class pipelineMonthView(SingleTableMixin, MonthMixin, ListView):
model = Job
table_class = JobTable
form_class = JobForm
bulk_actions = PipelineBulkActionsForm
template_name = "main_app/pipeline_by_month.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['job_form'] = self.form_class
context['bulk_actions'] = self.bulk_actions
context['year'] = 2023 #will be date.today().year
context['month'] = 2 #will be date.today().month
return context
def get_queryset(self):
queryset = super().get_queryset()
print(f'the result of self.get_month: {self.get_month()}')
queryset = queryset.filter(job_date=self.get_month())
return queryset
My URL, including URLs from main_app:
path('pipeline/<int:year>/<int:month>/', views.pipelineMonthView.as_view(model=Job), name="pipeline-by-month"),
And my URL tag: {% url 'main_app:pipeline-by-month' year month %}
My template is at static/main_app/pipeline_by_month.html
.
Here’s the traceback:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/core/handlers/base.py", line 204, in _get_response
response = response.render()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/response.py", line 105, in render
self.content = self.rendered_content
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/response.py", line 83, in rendered_content
return template.render(context, self._request)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/backends/django.py", line 61, in render
return self.template.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 170, in render
return self._render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 162, in _render
return self.nodelist.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/loader_tags.py", line 150, in render
return compiled_parent._render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 162, in _render
return self.nodelist.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/defaulttags.py", line 449, in render
url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/urls/base.py", line 86, in reverse
return resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/urls/resolvers.py", line 698, in _reverse_with_prefix
raise NoReverseMatch(msg)
Exception Type: NoReverseMatch at /main_app/
Exception Value: Reverse for 'pipeline-by-month' with arguments '('', '')' not found. 1 pattern(s) tried: ['main_app/pipeline/(?P<year>[0-9]+)/(?P<month>[0-9]+)/\Z']
Edit to add some more info:
My Job model is below. The ‘job_date’ attribute is calculated from ‘year’ and ‘month’ attributes, as the day of the month is not relevant in my app.
class Job(models.Model):
year = models.CharField(max_length=4, editable=True, default=date.today().year)
month = models.CharField(max_length=2, editable=True, default=date.today().month)
job_date = models.DateField(editable=False, null=True, default=timezone.now)
def save(self, *args, **kwargs):
self.job_date = f'{self.year}-{int(self.month):02d}-01'
super().save(*args, **kwargs)
Adding the html where I’m using the code. It’s in the navbar of my base.html file, so I’m just including that block.
{% block navbar %}
<nav class="navbar navbar-expand-lg bg-dark p-0" data-bs-theme="dark">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'admin:index' %}">
<img src="{% static 'main_app/images/bwcat_logo_720x720.png' %}" alt="Bootstrap" width="65" height="65">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="{% url 'main_app:pipeline' %}">Pipeline</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'main_app:pipeline-by-month' year month %}">Pipeline Monthly</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Clients
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'main_app:client-add' %}">Add Client</a></li>
<li><a class="dropdown-item" href="{% url 'main_app:client-list' %}">View Clients</a></li>
</ul>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Vendors
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'main_app:invoice-request-page' %}">Request Invoices</a></li>
<li><a class="dropdown-item" href="{% url 'main_app:vendor-add' %}">Add Vendor</a></li>
<li><a class="dropdown-item" href="{% url 'main_app:vendor-list' %}">View Vendors</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link disabled">Placeholder</a>
</li>
</ul>
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
{% endblock %}
Answers:
I assume you are using a block which will be reused multiple times. Hence the context variable month
and year
won’t be availbe in all the views. In this case, you need to use custom context processor
which are available in all pages. You can write one like this:
#yourapp/custom_context_processor.py
def get_year_month(request):
# you put your custom logic here
year = request.GET.get('year', 2023)
month= request.GET.get('month', 2)
return {
'year': year,
'month': month
}
Then add it to TEMPLATES
in your settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'your_app.custom_context_processor.get_year_month' #<-- here
],
},
},
]
Update
More simplified implementation can be like this using NOW
:
{% now "Y" as current_year %}
{% now "M" as current_month %}
{% url 'main_app:pipeline-by-month' current_year current_month %}
Banging my head against a wall.. I’m trying to return a table of Job objects, with views separated by month. I’m passing ‘year’ and ‘month’ variables through get_context_data, yet in my template they’re returning blank strings. Even ChatGPT can’t find anything wrong lol. Can anyone spot something?
Here’s my view:
class pipelineMonthView(SingleTableMixin, MonthMixin, ListView):
model = Job
table_class = JobTable
form_class = JobForm
bulk_actions = PipelineBulkActionsForm
template_name = "main_app/pipeline_by_month.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['job_form'] = self.form_class
context['bulk_actions'] = self.bulk_actions
context['year'] = 2023 #will be date.today().year
context['month'] = 2 #will be date.today().month
return context
def get_queryset(self):
queryset = super().get_queryset()
print(f'the result of self.get_month: {self.get_month()}')
queryset = queryset.filter(job_date=self.get_month())
return queryset
My URL, including URLs from main_app:
path('pipeline/<int:year>/<int:month>/', views.pipelineMonthView.as_view(model=Job), name="pipeline-by-month"),
And my URL tag: {% url 'main_app:pipeline-by-month' year month %}
My template is at static/main_app/pipeline_by_month.html
.
Here’s the traceback:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/core/handlers/base.py", line 204, in _get_response
response = response.render()
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/response.py", line 105, in render
self.content = self.rendered_content
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/response.py", line 83, in rendered_content
return template.render(context, self._request)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/backends/django.py", line 61, in render
return self.template.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 170, in render
return self._render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 162, in _render
return self.nodelist.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/loader_tags.py", line 150, in render
return compiled_parent._render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 162, in _render
return self.nodelist.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 938, in render
bit = node.render_annotated(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/base.py", line 905, in render_annotated
return self.render(context)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/template/defaulttags.py", line 449, in render
url = reverse(view_name, args=args, kwargs=kwargs, current_app=current_app)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/urls/base.py", line 86, in reverse
return resolver._reverse_with_prefix(view, prefix, *args, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/django/urls/resolvers.py", line 698, in _reverse_with_prefix
raise NoReverseMatch(msg)
Exception Type: NoReverseMatch at /main_app/
Exception Value: Reverse for 'pipeline-by-month' with arguments '('', '')' not found. 1 pattern(s) tried: ['main_app/pipeline/(?P<year>[0-9]+)/(?P<month>[0-9]+)/\Z']
Edit to add some more info:
My Job model is below. The ‘job_date’ attribute is calculated from ‘year’ and ‘month’ attributes, as the day of the month is not relevant in my app.
class Job(models.Model):
year = models.CharField(max_length=4, editable=True, default=date.today().year)
month = models.CharField(max_length=2, editable=True, default=date.today().month)
job_date = models.DateField(editable=False, null=True, default=timezone.now)
def save(self, *args, **kwargs):
self.job_date = f'{self.year}-{int(self.month):02d}-01'
super().save(*args, **kwargs)
Adding the html where I’m using the code. It’s in the navbar of my base.html file, so I’m just including that block.
{% block navbar %}
<nav class="navbar navbar-expand-lg bg-dark p-0" data-bs-theme="dark">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'admin:index' %}">
<img src="{% static 'main_app/images/bwcat_logo_720x720.png' %}" alt="Bootstrap" width="65" height="65">
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="{% url 'main_app:pipeline' %}">Pipeline</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'main_app:pipeline-by-month' year month %}">Pipeline Monthly</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Clients
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'main_app:client-add' %}">Add Client</a></li>
<li><a class="dropdown-item" href="{% url 'main_app:client-list' %}">View Clients</a></li>
</ul>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Vendors
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="{% url 'main_app:invoice-request-page' %}">Request Invoices</a></li>
<li><a class="dropdown-item" href="{% url 'main_app:vendor-add' %}">Add Vendor</a></li>
<li><a class="dropdown-item" href="{% url 'main_app:vendor-list' %}">View Vendors</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link disabled">Placeholder</a>
</li>
</ul>
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
{% endblock %}
I assume you are using a block which will be reused multiple times. Hence the context variable month
and year
won’t be availbe in all the views. In this case, you need to use custom context processor
which are available in all pages. You can write one like this:
#yourapp/custom_context_processor.py
def get_year_month(request):
# you put your custom logic here
year = request.GET.get('year', 2023)
month= request.GET.get('month', 2)
return {
'year': year,
'month': month
}
Then add it to TEMPLATES
in your settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'your_app.custom_context_processor.get_year_month' #<-- here
],
},
},
]
Update
More simplified implementation can be like this using NOW
:
{% now "Y" as current_year %}
{% now "M" as current_month %}
{% url 'main_app:pipeline-by-month' current_year current_month %}