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 %}
Asked By: Joe Connor

||

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 %}
Answered By: ruddra