I am trying to render two differents models using a loop in my templates/dashboard/home.html using Class Based View.
Let's have a look on my code :
views.py
class DashboardListView(ListView):
model = Links
template_name = 'dashboard/home.html'
class ContentListView(ListView):
model = Dashboard
template_name = 'dashboard/home.html'
First I would like to used the same ListView but was unable to do so.
My home.html
{% for dashboard in object_list %} {{dashboard.content}} {% endfor %}
{% for links in object_list %} {{links.content}} {% endfor %}
I would like to render those two models but I can only render one and the other object list will take the content for the preivous one.
Thanks for your help
First you can specify a different Mae for the list of your objects using:
context_object_name =‘links_list’
Then you can add different elements to the context extending this method:
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
# Add in a QuerySet
context[‘dashboard_list’]= Dashboard.objects.all()
return context
Related
I am creating a Q&A website for practice, I created the answer and the question model and linked them together, however I can not access the template that I set for the deletion of the answer model, I created a DeleteView to delete the question. Here is the code:
views.py:
class Politics_post_details(DeleteView):
model = PoliticsPost
context_object_name = 'politicsposts'
pk_url_kwarg = 'qid'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# now you can get any additional information you want from other models
question = get_object_or_404(PoliticsPost, pk=self.kwargs.get('qid'))
context['answers'] = Answer.objects.filter(post=question).order_by('-date_posted')
return context
class AnswerDelete(UserPassesTestMixin,DetailView):
model = Answer
success_url = reverse_lazy('Lisk home')
pk_url_kwarg = 'aid'
def test_func(self):
answer = self.get_object()
if self.request.user ==answer.author:
return True
return False
urls.py(not root):
path('politicspost/<int:qid>/createanswer/',views.CreateAnswer.as_view(template_name='lisk_templates/createanswer.html'),name = 'Answer'),
path('politicspost/<int:qid>/answer/<int:aid>/delete/',views.AnswerDelete.as_view(template_name = 'lisk_templates/answer_delete.html'),name='Answer_Delete'),
path('politicspost/<int:qid>/',views.Politics_post_details.as_view(template_name='lisk_templates/politics_post_details.html'),
I created the template but whenever I try to access it, it gives me an error as follows:
NoReverseMatch at /politicspost/29/
Reverse for 'Answer_Delete' with arguments '(36,)' not found. 1 pattern(s) tried: ['politicspost/(?P<qid>[0-9]+)/answer/(?P<aid>[0-9]+)/delete/$']
Thanks in advance.
answer_delete.html:
{%extends "lisk_templates/base.html"%}
{% block title %}
Page title
{% endblock title %}
{% block body%}
<div class="feed" style="background-color:lightred;"><form method="POST">
{% csrf_token %}
<h3>Are you sure that you want to delete this answer: <br>
{{ object.content }}</h3>
<button id="signin" type="submit">Yes</button> No
</form>
</div>
{% endblock body %}
You have a number of issues. The biggest one is that you have switched DeleteView and DetailView (your DeleteView is a DetailView and vice versa).
And then you should either rename your template to answer_confirm_delete or add the template_name_suffix to your DeleteView. See the documentation for further details:
https://docs.djangoproject.com/en/3.0/ref/class-based-views/generic-editing/#django.views.generic.edit.DeleteView
If you use Django's DeleteView, you don't need to specify a url in the template, it will do all the work for you. Just make sure you specify the url correctly in your urls.py. Fix these issues and see if it works then.
May Be This Might Work For You, Because You Never Used The Import Of DeleteView
from django.views.generic import DeleteView
"""This Is From My Blog App, That I Used For My Blog App, Hope This Will Help"""
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
success_url = reverse_lazy('post_list')
Happy Coding, let me know if there are any issues with this I'am Up for you!
I'm still getting used to class based views, while I get the general purpose, some things still get past me. I'm following a tutorial which basically walks you through the motions but tends to ignore the fuzzy details, such as this piece of code:
class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
"""Generic class-based view listing books on loan to current user."""
model = BookInstance
template_name ='books/bookinstance_list_borrowed_user.html'
paginate_by = 1
def get_queryset(self):
return BookInstance.objects.filter(
borrower=self.request.user
).filter(status__exact='o').order_by('due_back')
I get the model, template_name and paginate_by parts, they're attributes of the ListView class, but what I don't get is the get_queryset part, where is it executed? As seen in the code below it's called nowhere. Where is it returned to? I guess my first question can be chalked down to "What do functions in class based views do?"
{% extends "base_generic.html" %}
{% block content %}
<h1>Borrowed books</h1>
{% if bookinstance_list %}
<ul>
{% for bookinst in bookinstance_list %}
<li class="{% if bookinst.is_overdue %}text-danger{% endif %}">
{{bookinst.book.title}} ({{ bookinst.due_back }})
</li>
{% endfor %}
</ul>
{% else %}
<p>There are no books borrowed.</p>
{% endif %}
So, two issues, first, where did the get_queryset return to, and second, what is
bookinstance_list? It's not a context variable, but seems to be used out of the blue, why is this variable usable?
Class Based Views calls get_queryset() in the get() method of your view, I'll present some example code from Django 1.11.
# django/views/generic/list.py:159
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
allow_empty = self.get_allow_empty()
...
context = self.get_context_data()
return self.render_to_response(context)
The ListView class sets self.object_list = self.get_queryset() in this method, however this doesn't explain where it sets it in the context passed to your template. If we take a quick look at get_context_data():
# django/views/generic/list.py:127
def get_context_data(self, **kwargs):
"""
Get the context for this view.
"""
queryset = kwargs.pop('object_list', self.object_list)
page_size = self.get_paginate_by(queryset)
context_object_name = self.get_context_object_name(queryset)
if page_size:
paginator, page, queryset, is_paginated = self.paginate_queryset(queryset, page_size)
context = {
'paginator': paginator,
'page_obj': page,
'is_paginated': is_paginated,
'object_list': queryset
}
else:
context = {
'paginator': None,
'page_obj': None,
'is_paginated': False,
'object_list': queryset
}
if context_object_name is not None:
context[context_object_name] = queryset
context.update(kwargs)
return super(MultipleObjectMixin, self).get_context_data(**context)
context is assigned a dictionary with 'object_list': queryset, so when you're trying to access the resulting QuerySet from get_queryset in your template you should access object_list.
The Django documentation on class-based generic views has a section on extending your context data with additional info. https://docs.djangoproject.com/en/2.1/topics/class-based-views/generic-display/#dynamic-filtering
from django.views import generic
from .models import Inspectionfile
from .models import posts
class IndexView(generic.ListView):
template_name = "posts/index.html"
def get_queryset(self):
return Inspectionfile.objects.all()
class DetailView(generic.DetailView):
model = Inspectionfile
template_name = "posts/detail.html "
#index template
<ul>
{% for o in object_list %}
<li>{{o.document_title}} </li>
{% endfor %}
</ul>
#detail template
<h1>{{ o.document_title }}</h1>
My Index template works but the detail template does not seem to take the value so just appears blank . So is the 'o' not being passed to detail ?? I have not been able to solve this. BTW document_title is one of the field of my inspectionfile model. I checked my url regex and it seems to work fine.
o is an object which only exists within the for loop in your list view template. It isn't passed anywhere.
The detail view has its own context; there the object that is identifued by the url argument is called just object.
So i'm trying to filter my model in this way in views.py:
news_list = list(models.Entry.objects.filter(category='news'))
and the problem is that the list cant be accessable from the django templates.
this is the way I'm trying to access it in home.html:
{% for news in news_list %}
{{ news.title }}
{% endfor %}
and this:
{{ news_list.0.title }}
I'm sure the way that I created the list is right beauce when I loop through the list in the views.py it show up in the terminal.
I'm using python3.3 and django 1.8.3
views.py :
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.views import generic
from . import models
from blog.models import Entry
class BlogIndex(generic.ListView):
queryset = models.Entry.objects.published()
template_name = "home.html"
paginate_by = 3
news_list = Entry.objects.filter(category='news')
i = 0
for x in news_list:
i = i+1
print(x.title,i)
You are trying to access news_list in the template when it is infact not present in the template.
You need to pass news_list in the context data. Override the get_context_data() and pass this variable.
class BlogIndex(generic.ListView):
queryset = models.Entry.objects.published()
template_name = "home.html"
paginate_by = 3
def get_context_data(self, **kwargs):
context = super(BlogIndex, self).get_context_data(**kwargs)
context['news_list'] = Entry.objects.filter(category='news') # pass 'news_list' in the context
return context
Then in your template, you can use the normal for loop.
{% for news in news_list %}
{{ news.title }}
{% endfor %}
Note: You don't need to convert the QuerySet to a list as it is already an iterable.
The queryset result can be used to iterate in django template. So there is no need to convert query set object into list. List is not iterable in django template though python does. You can use django-mptt is a premade solution, which should fit your problem quite good.
That's because in django you don't access lists, but querysets. Try:
context['news_list'] = Entry.objects.filter(category='news')
My URL
/tags/{slug}
points to this view:
class TagsDetailList(request, ListView):
queryset = Link.objects.filter(tags__name__in=['request.slug'])
template_name = "links/tags_detail_list.html"
So i have the request.slug object in the url.
Now i want to make a ListView that filters Link.objects by request.slug and respond to given template with the queried result.
All works but no queries are given on my template.
response template is:
{% extends "base.html" %}
{% block content %}
<h2>Tags Detail List</h2>
<ul>
{% if link in object_list %}
{% for link in object_list %}
<li>
{{ link.title }}
</li>
{% endfor %}
{% else %}
<p> Error: No Links in queryset! </p>
{% endif %}
<ul>
{% endblock %}
i dont get some elements, only the error message. its something bad on the request on my view.
who can help me and give me a hint how i can retrieve the request slug on my view?
EDIT:
nice solutions. i learned the way kwargs work(a small part).
But on the template i get still the error for no queryset. Tried both answers and also changed a bit but never really worked. Any hint what cause this?
If your urls pattern something like this:
r'^list/(?P<slug>[\w,\*]+)?$'
So in the views should be:
class TagsDetailList(ListView):
model = Link
template_name = "links/tags_detail_list.html"
def get_queryset(self):
qs = self.model.objects.all()
if self.kwargs.get('slug'):
qs = qs.filter(tags__name=self.kwargs['slug'])
return qs
What you've done here doesn't make sense: you're just asking for tags whose names are in the list consisting of the literal text " request.slug".
You need to override get_queryset so that it queries on the actual value of the slug, which is in self.kwargs.
def get_queryset(self, *args, **kwargs):
return Link.objects.filter(tags__name=self.kwargs ['slug'])
Also, I don't know what that if statement is doing in your template, but you haven't defined "link" do it will never evaluate to true, so no links will show.
Maybe it will help, but it works for me in Django 2+:
Your urls.py:
...
path('tags/<slug>/', TagsDetailList.as_view(), name='tags_detail'),
...
Your views.py:
...
class TagsDetailList(ListView):
model = Link
template_name = 'links/tags_detail_list.html'
def get_queryset(self, *args, **kwargs):
return Link.objects.filter(tags__slug=self.kwargs['slug'])
...