Is it possible to render 2 queryset in ListView? - django

I am new to django and recently read a tutural that describes the usage of class based view. But when I try to render 2 different queryset (all data and filterd data) to the same template, I can't find the solution for display 2 different queryset. Can anyone suggest the best solution about this?
I know writing the function based view is much easy for this, but I hope it can be done by Class based view, thank you
#in view.py
from django.views.generic import ListView
from books.models import Book
class BookListView(generic.ListView):
model = Book
context_object_name = 'my_book_list'
queryset = Book.objects.all()
template_name = 'books/my_arbitrary_template_name_list.html'
# queryset = Book.objects.filter(title='war')?
#in templage.py
#Main content
<div class="main_content">
<h1>All War</h1>
<ul>
{% for book in book_list %}
<li>
{{book.title}}
</li>
{% for endfor %}
</ul>
</div>
#Sidebar
<div class="sidebar">
<h1>All War</h1>
<ul>
{% for book in book_list %}
<li>
{{book.title}}
</li>
{% for endfor %}
</ul>
</div>

You should look into get_context_data to add additional queries you want.
The view might look something like this
class BookListView(generic.ListView):
model = Book
context_object_name = 'my_book_list'
queryset = Book.objects.all()
template_name = 'books/my_arbitrary_template_name_list.html'
def get_context_data(self, **kwargs):
context = super(BookListView, self).get_context_data(**kwargs)
context['second_queryset'] = # YOUR QUERY HERE
return context
For this example the second query is second_queryset and it can be accessed in the html template as {{second_queryset}}. You can add more if you did the same for more queries.
def get_context_data(self, **kwargs):
context = super(BookListView, self).get_context_data(**kwargs)
context['second_queryset'] = # YOUR QUERY HERE
context['third_queryset'] = # YOUR QUERY HERE
...
return context
You can learn about it more in here.

Related

How to paginate a class-based list view with django-filters

Do you guys know how to paginate a generic class-based ListView that uses django-filters as a search bar? When I read some articles regarding this issue(which wasn't a lot for class-based views), it seems that django-filters and pagination don't work together very well. Here is my view:
class StudentListView(OrganisorAndLoginRequiredMixin, generic.ListView):
template_name = "leads/student_list.html"
context_object_name = "leads"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = StudentFilter(self.request.GET, queryset=self.get_queryset())
return context
def get_queryset(self):
organisation = self.request.user.userprofile
return Lead.objects.filter(organisation=organisation).order_by('first_name')
I would really appreciate it if you guys could tell me what code I need to write for my view as well as what code I need to add into my template to make pagination work. I don't think the code for the actual filter and the template is necessary, but if you guys need it, I can add it to this question. Thanks.
For additional information, I am going to add the following pagination code to my template:
{% 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 %}
You should use FilterView that is provided by django-filter. Also this class inherits from MultipleObjectMixin so it is capable of performing pagination, so if you set paginate_by attribute on the class it will perform pagination too:
from django_filters.views import FilterView
class StudentListView(OrganisorAndLoginRequiredMixin, FilterView):
template_name = "leads/student_list.html"
context_object_name = "leads"
filterset_class = StudentFilter
paginate_by = 10 # Change as per your preference
def get_queryset(self):
organisation = self.request.user.userprofile
return Lead.objects.filter(organisation=organisation).order_by('first_name')

How to make a filter in Django Listview queryset

I have a list of brands. Each brand has a list of categories
I want to make each brand a link. And when the user click the brand he passes to the page with all the categories related to that brand
Here is a template with brands:
<ul>
{% for brand in object_list %}
<li>{{ brand.name }}</li>
{% endfor %}
</ul>
And here is the view:
class CategoryListView(ListView):
model = Category
queryset = Category.objects.filter(brand=pk)
template_name = 'category_list.html'
But it gives an error. Can someone help me?
Thank you
Override get_queryset method:
class CategoryListView(ListView):
model = Category
template_name = 'category_list.html'
def get_queryset(self, **kwargs):
qs = super().get_queryset(**kwargs)
return qs.filter(brand_id=self.kwargs['pk'])
And the url should look like this:
path('category/<int:pk>/', CategoryListView.as_view())

Visibility of a Django formview in templates

I've followed the tutorial here to implement a basic search function: https://learndjango.com/tutorials/django-search-tutorial
I'd like to extend that tutorial by making the search function visible on the results page, allowing for repeated search. However, when I do this I can't get the search form to show up on the search results page. The search button shows up, but not the field to provide input.
Relevant code:
home.html:
<div name="searchform">
<form action="{% url 'search_results' %}" method="get">
{{ form }}
<input type="submit" value="Search">
</form>
</div>
{% block content %}
{% endblock %}
search_results.html:
{% extends home.html}
{% block content %}
<h1>Search Results</h1>
<ul>
{% for city in object_list %}
<li>
{{ city.name }}, {{ city.state }}
</li>
{% endfor %}
</ul>
{% endblock %}
Views.py:
from django.db.models import Q
from django.views.generic import TemplateView, ListView, FormView
from .models import City
class HomePageView(FormView):
template_name = 'home.html'
form_class = SearchForm
class SearchResultsView(ListView):
model = City
template_name = 'search_results.html'
def get_queryset(self):
query = self.request.GET.get('q')
object_list = City.objects.filter(
Q(name__icontains=query) | Q(state__icontains=query)
)
return object_list
urls.py:
from django.urls import path
from .views import HomePageView, SearchResultsView
urlpatterns = [
path('search/', SearchResultsView.as_view(), name='search_results'),
path('', HomePageView.as_view(), name='home'),
]
forms.py:
from django import forms
class SearchForm(forms.Form):
q = forms.CharField(label='', max_length=50,
widget=forms.TextInput(attrs={'placeholder': 'Search Here'})
)
Any advice on how I might troubleshoot this sort of issue (or if I'm blatantly doing something un-django-y) would be greatly appreciated.
You're using ListView which is a Generic display view.
You need to use get method, then you can pass the form to make the search again and stay on the same page.
class SearchResultsView(View):
template_name = 'search_results.html'
form_class = SearchForm
def get(self, request):
form = self.form_class()
query = self.request.GET.get('q')
context = {}
context['form'] = form
context['cities'] = City.objects.filter(
Q(name__icontains=query) | Q(state__icontains=query)
)
return render(self.request, self.template_name, context)
You can achieve the same result with ListView but is better if you use other based view class.
You can check the doc. here
class HomePageView(FormView):
template_name = 'home.html'
form_class = SearchForm # This line!
Remember to also apply the form_class attribute to SearchResultsView, otherwise, no forms will be interpreted. The submit button only shows up because it's not a part of the rendered form.

django list_filter in html

How do i import this list_filter into my html? do you have any documentation that easy to follow and easy to understand? is it possible?
class ArticleListView(ListView):
model = StudentsEnrollmentRecord
s=StudentsEnrollmentRecord.objects.all()
paginate_by = 50 # if pagination is desired
searchable_fields = ["Student_Users", "id", "Section"]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['now'] = timezone.now()
return context
You can use template tags to loop your object and populate your html:
https://docs.djangoproject.com/en/3.0/ref/templates/builtins/
To give you a kickstart:
<ul>
{% for filter in s %}
<li>{{ filter.Student_Users }}</li>
{% endfor %}
</ul>
This will basically create one <li> per each item in your queryset.
Make sure that the required data is returned properly from your view via the context:
context = {
'queryset': s,
}
return (context)

How to make groups of all the Customers, Admins and Staff Members and render accordingly in same template based on URL hit?

I am trying to show all the Customers, Superusers and Staff members in a same template. How can I do this? I have a running code like this
class GroupListView(UserPassesTestMixin, ListView):
model = User
template_name = 'admin_app/group_list.html'
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(**kwargs)
group_name = (self.kwargs['group'])
if group_name == 'admin':
context['user_list']= User.objects.filter(is_superuser=True, is_staff=True)
elif group_name == 'staff':
context['user_list'] = User.objects.filter(is_staff=True)
else:
context['user_list'] = User.objects.filter(is_superuser=False, is_staff=False)
return context
def test_func(self):
return self.request.user.is_superuser
and the urls which produce hits are like this
<i class="fa fa-adn"></i>Admin
Template is big so there is no need to post that. This is producing results but is there a better way to do this?
How can I make Groups and then render the data?
NOTE- How can I just make a link and view that will sort all the Users according to the link clicked. (same way in Django- Admin)
When assigning users to Groups you can create as many groups as you like.
If you want to dynamically create urls for all groups and show a list of users belonging to that group you could do this:
To create the urls:
For example on your userListView add group to the context. Then in the get_queryset method you can check if the kwarg 'group' is available. If it is available you filter the queryset based on that.
from django.contrib.auth.models import Group
class UsersListView(ListView):
model = User
template_name = 'user_list.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['groups'] = Group.objects.all()
return context
def get_queryset(self):
queryset = super().get_queryset()
try:
group = self.kwargs['group']
queryset = queryset.filter(groups=group)
except:
pass
return queryset
then in your template:
{% extends 'base.html' %}
{% block content %}
<div class="col-md-10">
<table>
{% for object in object_list %}
<tr><td>{{ object }}</td></tr>
{% endfor %}
</table>
</div>
<div class="col-md-2">
<table class="table">
{% for group in groups %}
<tr>
<td>{{ group }}</td>
</tr>
{% endfor %}
</table>
</div>
{% endblock %}
in urls.py you van add two routes to the same view:
path('users/', views.UsersListView.as_view(), name='user_list'),
path('users/<group>/', views.UsersListView.as_view(), name='user_list'),
Indentation is a bit off, but you get the point.