.Hello everyone! I am a beginner in Django and I know that this question was asked hundrets of times on SO, but I still can't get it. I tried to use two models in the same IndexView, but it just repeats the elements which contains in the Petition model.
class IndexView(generic.ListView):
template_name = 'home.html'
context_object_name = 'home_list'
model = Petition
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['petition'] = Petition.objects.all()
context['law'] = Law.objects.all()
return context
And here is a relevant part of the template:
{% if home_list %}
<ul>
{% for petition in home_list%}
<li>{{ petition.question }}</li>
<img src="{{ petition.image.url }}" height="200" width="300">
{% endfor %}
</ul>
{% else %}
<p>No petitions are available.</p>
{% endif %}
{% if home_list %}
<ul>
{% for law in home_list %}
<li>{{ law.question }}</li>
<img src="{{ law.image.url }}" height="200" width="300">
{% endfor %}
</ul>
{% else %}
<p>No laws are available.</p>
{% endif %}
You're defining your law list in the context as law but then you never reference it, you should be looping over these instead of home_list
{% if law %}
{% for l in law %} {# law is already defined so cant be used as scope var #}
Related
I was looking for a solution but nowhere to find the right answer. Maybe the answer I am looking for does not exist, so I decided to ask a question here just in case.
I try to show a date without a day. But the problem is that the date is displayed as one of form fields that I create from the model in the database. I explained this because I am not trying to show only the date separately in the temple but the whole form. I'm showing the form in the template using {{form.as_p}}. My date always shows dd.mm.YYYY, but I want to display a date without a day. The form is used to update existing data in the database. Is there a solution, to define certain parameters in the form class I created in the forms.py file or I must do something else?
Suppose this is your forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=30)
email = forms.EmailField(max_length=254)
message = forms.CharField(
max_length=2000,
widget=forms.Textarea(),
help_text='Write here your message!'
)
source = forms.CharField( # A hidden input for internal use
max_length=50, # tell from which page the user sent the message
widget=forms.HiddenInput()
)
You can render it manually like this:
<form method="post" novalidate>
{% csrf_token %}
{% if form.non_field_errors %}
<ul>
{% for error in form.non_field_errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{% for hidden_field in form.hidden_fields %}
{% if hidden_field.errors %}
<ul>
{% for error in hidden_field.errors %}
<li>(Hidden field {{ hidden_field.name }}) {{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{{ hidden_field }}
{% endfor %}
<table border="1">
{% for field in form.visible_fields %}
<tr>
<th>{{ field.label_tag }}</th>
<td>
{% if field.errors %}
<ul>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
{{ field }}
{% if field.help_text %}
<br />{{ field.help_text }}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<button type="submit">Submit</button>
</form>
Now you can apply date filter to your fields:
{{ value|date:"D d M Y" }}
You can read more about date filter as pre your need i.e., to get only date or time : https://docs.djangoproject.com/en/2.2/ref/templates/builtins/#date
So I have this Lecture class. Now for this class, I have 2 choices: "Classes" and "Seminars", and I want that each time I add a lecture to either one, the template will shows firstly the choice and then all the lectures.
Example: Classes will have Lecture1, Lecture2, Lecture3 etc.
Problem is that right now when I iterate, choice shows each time, for every lecture and I want each choice to show only ONCE.
class Lecture(models.Model):
course = models.ForeignKey('Course', on_delete=models.CASCADE, default='', related_name='lectures')
lecture_category = models.IntegerField(choices=((0, "Classes "),
(1, "Seminars"),
))
lecture_title = models.CharField(max_length=100)
content = models.TextField()
link = models.URLField(blank=True)
file = models.FileField(upload_to='documents', blank=True)
def __str__(self):
return self.lecture_title
<ul>
{% for c in lectures %}
<b>{{ c.get_lecture_category_display }}</b>
<p>.......................</p>
<li>{{ c.lecture_title }}</li>
<li>{{ c.content }}</li>
{% if c.link %}
<li>{{ c.link }}</li>
{% if c.file %}
<li><a href='{{ MEDIA_URL }}{{ c.file.url }}'>download</a></li>
{% endif %}
{% endif %}
{% endfor %}
<hr/>
</ul>
There is a template tag called regroup that you can use for this. See the regroup section at https://docs.djangoproject.com/en/2.0/ref/templates/builtins/
{% regroup lectures by lecture_category as category_list %}
<ul>
{% for category in category_list %}
<li>{{ category.grouper }}
<ul>
{% for c in category.list %}
<li>{{ c.lecture_title }}</li>
<li>{{ c.content }}</li>
...etc
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Edit:
As Daniel Rosemen pointed out, you will also have to sort the query by the field you want to regroup on in your view. In this case you would have to order lectures by lecture_category. The above method will not work otherwise.
Here are my codes(it works fine):
#views.py
class IndexView(generic.ListView):
template_name = 'index.html'
context_object_name = 'home_list'
queryset = Song.objects.all()
paginate_by = 1
def get_context_data(self, **kwargs):
context = super(IndexView, self).get_context_data(**kwargs)
context['all_artists']=Artist.objects.all()
context['all_songs']=Song.objects.all()
context['all_albums']=Album.objects.all()
return context
base.html(which is extended by index.html):
#base.html
{% block content %}{% endblock %}
{% block pagination %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
Previous
{% endif %}
<span class="page-current">
Page {{page_obj.number}} of {{page_obj.paginator.num_pages }}
</span>
{% if page_obj.has_next %}
Next
{% endif %}
</span>
</div>
{% endif %}
{% endblock %}
And my index.html:
{% extends 'base_generic.html' %}
{% block title %}<title>Listen to songs </title>{% endblock %}
{% block content %}
<h3>Best Songs</h3>
{% for song in all_songs %}
<ol>
<li>{{song.song_title}} <img src="{{song.song_logo}}" heigt=112, width=114/> <br></li>
</ol>
{% endfor %}
<h3>Best Albums</h3>
{% for album in all_albums %}
<ul>
<li title="{{album.album_title}}">
<img id="img_{{album.id}}" src="{{album.album_logo}}" heigt=112, width=114 />
<p>{{album.album_title}}</p>
</li>
</ul>
{% endfor %}
{% endblock %}
So when I compiled this, I got this window :
Image here
But in all pages, it stays the same.What I want is to display 1 song per page.Help guys !!!! :] :] :]
You never use your paginated objects, instead you've made a separate context variable called all_songs.
Simply just use the right context data
{% for song in all_songs %}
should be
{% for song in home_list %}
You may want to apply pagination for your other querysets too although it can get confusing paginating more than one list
Have a look here: https://www.youtube.com/watch?v=q-Pw7Le30qQ
The video explains pagination.
Alternative: https://docs.djangoproject.com/en/1.10/topics/pagination/
If you only want to display one song there is always the option to use a DetailView, which will only show one item.
Here is a stackoverflow question that describes the process for class based views: How do I use pagination with Django class based generic ListViews?
In your example: you don't have to set the queryset. Remove queryset = ### and add model = #YOURMODELNAME#.
If you want to overwrite the queryset you should do it in def get_queryset() which is a function of ListView. Like this:
class SongView(ListView):
model = Song
template_name = 'template_name'
def get_queryset():
queryset = super(SongView, self).get_queryset(**kwargs)
queryset = #aditional filters, ordering, whatever#
return queryset
I've been using django built-in pagination (is_paginated) in few of my pages. They are all working fine. Except for the search page where the pagination should only appear based on the filtered queryset.
I've checked through few other thread but it ain't helping much.
How do I use pagination with Django class based generic ListViews?
Django template tag exception
Here's a mini version of what I have so far:-
1)views.py
class SearchBookView(ListView):
template_name = 'books/search_book.html'
paginate_by = '2'
context_object_name = 'book'
form_class = SearchBookForm
def get(self, request):
form = self.form_class(request.GET or None)
if form.is_valid():
filtered_books = self.get_queryset(form)
context = {
'form' : form,
'book' : filtered_books,
}
else:
context = {'form': form}
return render(request, self.template_name, context)
def get_queryset(self, form):
filtered_books = Book.objects.all()
if form.cleaned_data['title'] != "":
filtered_books = filtered_books.filter(
title__icontains=form.cleaned_data['title'])
return filtered_books
def get_context_data(self):
context = super(SearchBookView, self).get_context_data()
return context
2) search_book.html (template)
{% crispy form %}
{% if book %}
<p>Found {{ book|length }} book{{ book|pluralize }}.</p>
{% for book in book %}
<div class="card">
<div style="height:170px; border:solid #111111;" class="col-md-3">
Ima
</div>
<div class="whole-card col-md-9">
<div class="title">"{{ book.title }}"</div>
<div>{{ book.description }}</div>
Read More
</div>
</div>
{% endfor %}
{% else %}
<p>No book matched your searching criteria.</p>
{% endif %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
previous
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
next
{% endif %}
</span>
</div>
{% endif %}
forms.py
class SearchBookForm(forms.Form):
title = forms.CharField(max_length=20)
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.add_input(Submit('search', 'Search', css_class='btn'))
self.helper.form_method = 'GET'
self.helper.layout = Layout('title')
super(SearchBookForm, self).__init__(*args, **kwargs)
------------------UPDATE------------------
Though I understand Daniel Roseman's answer but as I am fairly new to django, I am not sure how to implement the whole thing, hitting plenty of "X not accessible, X is not attribute of Y" and etc. After much digging, I found some other useful posts on this same matter.
Django: Search form in Class Based ListView
Updating context data in FormView form_valid method?
Django CBV: Easy access to url parameters in get_context_data()?
Django class based view ListView with form
URL-parameters and logic in Django class-based views (TemplateView)
Another problem I encounter is I am unable to access the parameters in URL using self.kwargs as what suggested in most of the posts. In the final link I posted above, Ngenator mentioned that URL parameters has to be accessed using request.GET.get('parameter'). I used that and it's working fine for me.
By combining everything, here's the revised piece of coding I have. Just in case anyone is having the same problem as me.
1) views.py
class SearchBookView(ListView):
template_name = 'books/search_book.html'
paginate_by = '3'
context_object_name = 'book_found'
form_class = SearchBookForm
model = Book
def get_queryset(self):
object_list = self.model.objects.all()
title = self.request.GET.get('title', None)
if title is not None and title != "":
object_list = object_list.filter(title__icontains=title)
else:
object_list = []
return object_list
def get_context_data(self):
context = super(SearchBookView, self).get_context_data()
form = self.form_class(self.request.GET or None)
context.update({
'form': form,
})
return context
2) search_book.html (template)
{% extends "base.html" %}
{% load crispy_forms_tags %}
{% load staticfiles %}
{% load bootstrap_pagination %}
{% block title %}Search Page{% endblock %}
{% block content %}
<div class="container">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
{% crispy form %}
{% if book_found %}
<p>Found {{ paginator.count }} book{{ book_found_no|pluralize }}.</p>
{% for book in book_found %}
<div class="wholecard">
<div style="height:170px; border:solid #111111;" class="col-md-3">
Image
</div>
<div class="card col-md-9">
<div class="card-title">"{{ book.title }}"</div>
<div>{{ book.description }}</div>
Read More
</div>
</div>
{% endfor %}
{% else %}
<p>No book matched your searching criteria.</p>
{% endif %}
{% bootstrap_paginate page_obj %}
</div>
{% endblock %}
And I ended up using jmcclell's bootstrap-pagination also for pagination. Saved me lots of time! Good stuff...
You've specifically overridden the get method so that it defines its own context, and never calls the default methods, so naturally none of the default context bars are available.
Don't do that; you should almost never be overriding the get and post methods. You should probably move all the form stuff directly into get_queryset.
It's working
views.py
class UserListView(ListView):
model = User
template_name = 'user_list.html'
context_object_name = 'users'
paginate_by = 10
def get_queryset(self):
return User.objects.all()
templates/user_list.html
{% if is_paginated %}
<nav aria-label="Page navigation conatiner">
<ul class="pagination justify-content-center">
{% if page_obj.has_previous %}
<li>« PREV </li>
{% else %}
<li class="disabled page-item"><a class="page-link">PREV !</a></li>
{% endif %}
{% for i in %}
{{ i }}
{% endfor %}
{% if page_obj.has_next %}
<li> NEXT »</li>
{% else %}
<li class="disabled page-item"><a class="page-link">NEXT !</a></li>
{% endif %}
</ul>
</nav>
</div>
{% endif %}
Hay, I'm using MPTT to create some tree-like data from a model which contains conversations, and i want them to be ordered by a 'votes' field.
The model looks like this at the moment, very basic.
class Thread(MPTTModel):
message = models.CharField(max_length=100)
parent = models.ForeignKey('self', null=True, blank=True, related_name='children')
votes = models.IntegerField()
class MPTTMeta:
order_insertion_by=['votes']
As you can see, we have a message field, and parent FK which is linked to the Thread model, and a votes.
Within my views i have this
threads = Thread.tree.all()
data = {
'threads':threads
}
return render_to_response("show.html",data )
then within my template
{% load mptt_tags %}
<ul class="root">
{% recursetree d %}
<li>
{{ node.title }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
However, the outputted list is a a list of all the threads. None of them are linked together.
Any ideas?
{% load mptt_tags %}
<ul class="root">
{% recursetree nodes %}
<li>
{{ node.message }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
In views I have:
threads = Thread.tree.all()
data = {
'nodes':threads
}
return render_to_response("show.html",data )
In the html page I see a tree of nodes order alphabetically and with indentation.