Django displays incorrect template - python

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.

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)

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> Performed on {{calc.time_calculated}}
</li>
{% endfor %}
</ul>
New for loop:
<ul>
{% for calc in calculation_list %}
<li> Performed on {{calc.time_calculated}}
</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.

Related

Codes in one of my views are not processed when I access to that view

My intention is to change from interface view -> switch view to process some data and send those data and change to -> test view to display the result. However, nothing in switch view seems to be processed and switch view doesn't change to test view after I hit 'submit' on userInterface.html. My guess is that the problem lies on the HttpResponseRedirect() function or anything related to url paths. Everything worked find with my other project that I worked on my computer. I'm not sure what I need to change to use Django on RaspberryPi.
At first, I found out I didn't import libraries needed for those function. After I imported them, the code was still not working.
I commented out other codes in switch view that do nothing with changing views and just focus on changing view in my switch view.
view.py
def user_interface(request):
return render(request,'zuumcoin/userInterface.html',
{})
def switch(request):
return HttpResponseRedirect(reverse('zuumcoin:test'))
def test(request):
return render(request,'zuumcoin/test.html',{})
userInterface.html
....
<form action="{% url 'zuumcoin:swicht' %} method = "POST">
{% csrf_token %}
...
...
</form>
urls.py
app_name='zuumcoin'
urlpatterns = [
url(r'', views.user_interface, name='interface'),
url(r'switch/', views.switch, name='switch'),
url(r'test/', views.test, name='test')
]
I expect HttpResponseRedirect to direct me to test view instead of being stuck in switch view. If it can do that, I think I can find a way for other part of my code in my switch view to run.
You didn't terminate your regexes. So the first pattern matches every path.
You should do:
url(r'^$', views.user_interface...)
It seems you have typo in your userInterface.html template. change this:
{% url 'zuumcoin:swicht' %}
to this one:
{% url 'zuumcoin:switch' %}

list view and details view in django

i want to create django project with two templates main list and details from the main list using genetic views List view and details views.
the main list work but not work details list.
this my code can somebody to help me ?
urls.py
urlpatterns = [
url(r'^$', ListView.as_view(
model = Test,
queryset = Test.objects.all(),
context_object_name = "test_list",
template_name='blog\test_list.html')),
url((r'^(?P<pk>\d+)-(?P<slug>[-\w]+)/$', DetailView.as_view(
context_object_name="test_list1",
model=Test,
template_name='blog\Test_details.html'
), name="test"),
]
html code test_list
{% for test in test_list %}
<h2> {{test.Title}}</h2>
{% endfor %}
html code test_details
<h2>{{ test.Title }}</h2>
Your link doesn't match your URLs: you're just passing the ID in your link, but the URL pattern is expecting the link and the slug.
I think your problem is a couple of typos:
First in urls, you should change this:
url((r'^(?P<pk>\d+)-(?P<slug>[-\w]+)/$', DetailView.as_view(
to this:
url((r'^(?P<pk>\d+)/$', DetailView.as_view(
Second, (again for the DetailView) your context_object_name is set to test_list1 but your template uses test (the two should match; considering there is no list in this detail view, I would change them to test).
Third, your template_name is set as blog\Test_details.html with the capital T while your html file is actually with lower case t
yeah that correct we success(just delete -(?P[-\w]+) ) to connect first and second template but the second template my Test.Title is empty not show me details from my database,if i use {%for%} show me error message

How to split django apps if shared view

There is a common case I encounter, where I can't find a way to split apps.
The case is when a info of two models is related and needs to be in the same template
An example speaks 1000 words: (2 models - pages + comments).
# models.py
class Page(models.Model):
title = models.CharField()
content = models.TextField()
class Comment(models.Model):
page = models.ForeignKey('Page')
content = models.TextField()
# url.py
...
url(r'^page/(?P<page_pk>\d+)/$', views.ViewPage, name='page-view-no-comments'),
url(r'^comment/(?P<comment_pk>\d+)/$', views.ViewComment, name='comment-view'),
url(r'^page-with-comments/(?P<page_pk>\d+)/$', views.ViewPageWithComments, name='page-view-with-comments'),
...
# views.py
def ViewPage(request, page_pk):
page = get_object_or_404(Page, pk=page_pk)
return render(request, 'view_page.html', {'page':page,})
def ViewComment(request, comment_pk):
comment = get_object_or_404(Comment, pk=comment_pk)
return render(request, 'view_comment.html', {'comment':comment})
def ViewPageWithComments(request, page_pk):
page = get_object_or_404(Page, pk=page_pk)
page_comments = Comment.objects.filter(page=page)
return render(request, 'view_page.html', {'page':page,'page_comments':page_comments'})
In this situation, splitting to Page app and Comment app is problematic, because they share a view (ViewPageWithComments) and url.
My options are:
1) Create an Ajax call to comments, which has crawling problems although Google might have fixed it lately.
2) Create a method of page that calls a method in the comments app that returns html with the comments content. If the method needs more arguments I also need to write a custom filter tag.
3) Decide not to split...
Am I missing something and there's another option? When would you prefer (1) vs (2) ?
Note - I created a very simple example to keep the problem general.
You don't need to split anything, you have the pages, and comments have a foreign key to that so you can just iterate over the pages comments
{% for page in pages %}
{% for comment in page.comment_set.all %}
{% endfor}
{% endfor %}
If you want to be able to use the same template for a version of this page without comments you can just wrap the comment for loop in an {% if show_comments %} statement

Django pass render_to_response template in other template

this is probably a question for absolute beginners since i'm fairly new to progrmaming. I've searched for couple of hours for an adequate solution, i don't know what else to do.
Following problem. I want to have a view that displays. e.g. the 5 latest entries & 5 newest to my database (just an example)
#views.py
import core.models as coremodels
class LandingView(TemplateView):
template_name = "base/index.html"
def index_filtered(request):
last_ones = coremodels.Startup.objects.all().order_by('-id')[:5]
first_ones = coremodels.Startup.objects.all().order_by('id')[:5]
return render_to_response("base/index.html",
{'last_ones': last_ones, 'first_ones' : first_ones})
Index.html shows the HTML content but not the content of the loop
#index.html
<div class="col-md-6">
<p> Chosen Items negative:</p>
{% for startup in last_ones %}
<li><p>{{ startup.title }}</p></li>
{% endfor %}
</div>
<div class="col-md-6">
<p> Chosen Items positive:</p>
{% for startup in first_ones %}
<li><p>{{ startup.title }}</p></li>
{% endfor %}
Here my problem:
How can I get the for loop to render the specific content?
I think Django show render_to_response in template comes very close to my problem, but i don't see a valid solution there.
Thank you for your help.
Chris
--
I edited my code and problem description based on the solutions provided in this thread
the call render_to_response("base/showlatest.html"... renders base/showlatest.html, not index.html.
The view responsible for rendering index.html should pass all data (last_ones and first_ones) to it.
Once you have included the template into index.html
{% include /base/showlatest.html %}
Change the view above (or create a new one or modify the existing, changing urls.py accordingly) to pass the data to it
return render_to_response("index.html",
{'last_ones': last_ones, 'first_ones' : first_ones})
The concept is that the view renders a certain template (index.html), which becomes the html page returned to the client browser.
That one is the template that should receive a certain context (data), so that it can include other reusable pieces (e.g. showlatest.html) and render them correctly.
The include command just copies the content of the specified template (showlatest.html) within the present one (index.html), as if it were typed in and part of it.
So you need to call render_to_response and pass it your data (last_ones and first_ones) in every view that is responsible for rendering a template that includes showlatest.html
Sorry for the twisted wording, some things are easier done than explained.
:)
UPDATE
Your last edit clarified you are using CBV's (Class Based Views).
Then your view should be something along the line:
class LandingView(TemplateView):
template_name = "base/index.html"
def get_context_data(self, **kwargs):
context = super(LandingView, self).get_context_data(**kwargs)
context['last_ones'] = coremodels.Startup.objects.all().order_by('-id')[:5]
context['first_ones'] = coremodels.Startup.objects.all().order_by('id')[:5]
return context
Note: personally I would avoid relying on the id set by the DB to order the records.
Instead, if you can alter the model, add a field to mark when it was created. For example
class Startup(models.Model):
...
created_on = models.DateTimeField(auto_now_add=True, editable=False)
then in your view the query can become
def get_context_data(self, **kwargs):
context = super(LandingView, self).get_context_data(**kwargs)
qs = coremodels.Startup.objects.all().order_by('created_on')
context['first_ones'] = qs[:5]
context['last_ones'] = qs[-5:]
return context

User authentication in Django

I learned how to authenticate users in Django months ago, but I've since upgraded and am having some problems so it occurred to me this morning that I may not have been doing it correctly from the start so I decided to ask.
In my project's urls.py file I've got ^accounts/login/$ and ^accounts/logout/$ both wired up to the built-in login() and logout() views (at django.contrib.auth.views) and ^accounts/profile/$ is connected to a view I've written, called "start_here" whose contents are basically this:
def start_here(request):
if request.user:
user_obj = request.user
else:
user_obj = None
is_auth = False
if request.user.is_authenticated():
is_auth = True
return render_to_response("profile.html", {'auth': is_auth,'user': user_obj,})
Now, "profile.html" extends a master template, called master.html, inside which is a "navbar" block whose contents are supposed to change if 'auth' == True (snippet below)
{% block navbar %}
{% if auth %}
Link A
Link B
Link C
Link D
Link E
Link F
Logout
{% else %}
Login
{% endif %}
{% endblock %}
My problem is that when I log in, and it redirects to /accounts/profile, the navbar doesn't display Links A-F + Logout, it displays only "login". It doesn't work the way I expect it to unless I manually copy-paste the above block into profile.html. When calling render_to_response(), does the context I provide get passed to the parent template as well as the child?
Full source to master and profile.html: http://dpaste.com/hold/128784/
I don't see anything suspect in the code.
This answer is tangential, but Jim's suggestion to use RequestContext is so good I want to explicitly explain how to do it.
You can reduce your start_here function to
from django.template import RequestContext
def start_here(request):
return render_to_response("profile.html", {},
context_instance=RequestContext(request))
By using RequestContext, user is automatically added to the context. Instead of using
{% if auth %}
use
{% if user.is_authenticated %}
Yes the context you pass in render_to_response() is passed to the named templates and ALL the templates it includes or inherits from.
You should look into Using RequestContext
Another thing to check...
Just making sure:
your profile template begins with
{% extends 'master.html' %}
In order to make sure django correctly identifies users, you need to make sure it is properly enabled in your settings module. specifically, you need to make sure that the SessionMiddleware and AuthenticationMiddleware modules are enabled in your settings.MIDDLEWARE_CLASSES. also be sure that auth is in your installed apps and you have run syncdb since enabling it.
If you have not taken the above steps, then django will not be able to detect when users have logged in and perform request setup properly.

Categories