Fatima
Fatima

Reputation: 61

Django displays incorrect template

I'm working on an website where user (if logged in) can perform a calculation and see all of his calculations listed. My website has two groups: Clients and Administrators where Clients are not allowed to see any other members' calculations except their own while Administrators are. Authentication is based on Django's built in User class and for each group I created separate views and templates. Templates have similar behavior but different displaying messages. When Clients want to see their calculations, correct information is displayed but the template rendered is for Administrators rather than for Clients.

views.py

#Administrators' view function
class CalculationListView(generic.ListView):
    model = Calculation
    paginate_by = 10


#Users' view function
class CalculationsByUserListView(LoginRequiredMixin, generic.ListView):
    model = Calculation
    paginate_by = 10
    
    def get_queryset(self):
       return Calculation.objects.filter(userid=self.request.user)

urls.py

urlpatterns = [
    path('', views.index, name='index'),
    path('calculations/', views.CalculationListView.as_view(), name='calculations'),
    path('calculation/<int:pk>', views.CalculationDetailView.as_view(), name='calculation-detail'),
]

urlpatterns += [
    path('mycalculation/', views.CalculationsByUserListView.as_view(), name='mycalcs'),
]

Template names

Administrators: calculation_list.html
Clients: calculations_user.html

EDIT: I mistakenly posted wrong test function. So, here's the one that produced the output referenced few lines below.

test.py

def test_logged_in_uses_correct_template(self):
        login = self.client.login(username='testuser1', password='1X<ISRUkw+tuK')
        response = self.client.get(reverse('mycalcs'))

        # Check if user is logged in
        self.assertEqual(str(response.context['user']), 'testuser1')
        # Check for the response "success"
        self.assertEqual(response.status_code, 200)

        # Check if correct template used
        self.assertTemplateUsed(response,'cycle/calculations_user.html')

Test response

======================================================================
FAIL: test_logged_in_uses_correct_template (cycle.tests.test_views.CalculationsByUserListViewTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Users\DEBIEVEL\Desktop\Work\Edited\django_test\orc2\cycle\tests\test_views.py", line 80, in test_logged_in_uses_correct_template
    self.assertTemplateUsed(response, 'cycle/calculations_user.html')
  File "C:\ProgramData\Anaconda3\lib\site-packages\django\test\testcases.py", line 661, in assertTemplateUsed
    % (template_name, ', '.join(template_names))
AssertionError: False is not true : Template 'cycle/calculations_user.html' was not a template used to render the response. Actual template(s) used: cycle/calculation_list.html, base_generic.html

I tried changing mappings and names of the urls but than I get NoReverseMatch error when I run server but the above test passes. I'm not sure where exactly did I mess up so any help is welcome.

Upvotes: 1

Views: 254

Answers (2)

Fatima
Fatima

Reputation: 61

So the issue wasn't in the view definition but in the template. Once I applied @Willem Van Onsem's solution, I started getting NoReverseMatch error for part of my template that actually displays the list. Upon further inspection I discovered it is the for loop in the template that actually raised an error. Since I haven't posted template code before, we were not able to spot it earlier.

The old for loop:

<ul>
    {% for calc in calculation_list %}
        <li> <a href="{% url 'calculation-detail' calc.user.pk %}"> Performed on {{calc.time_calculated}}</a>
        </li>
    {% endfor %}
</ul>

New for loop:

<ul>
    {% for calc in calculation_list %}
        <li> <a href="{{ calc.get_absolute_url }}"> Performed on {{calc.time_calculated}}</a>
        </li>
    {% endfor %}
</ul>

I also needed to move this specific template out of the templates/cycle folder to only templates/ Once, that was done, everything worked fine.

Upvotes: 0

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476534

You should specify the name of the templates in the ListViews. By default a ListView [Django-doc] will use the name of the model (here calculation), and then add a suffix _list to it, this thus means that a ListView with Calculation as model, will render the calculation_list.html template.

But this makes no sense for the CalculationsByUserListView, you thus should specify the template_name [Django-doc] with:

class CalculationsByUserListView(LoginRequiredMixin, generic.ListView):
    model = Calculation
    paginate_by = 10
    template_name = 'calculations_user.html'
    
    def get_queryset(self):
       return Calculation.objects.filter(userid=self.request.user)

Upvotes: 1

Related Questions