Setting GET parameters in url in Django - python

I want to create a listview with various optional filters. My url should be look like this:
shop/category_6/?manufacturer_id=3
And it works well when I put this url just in to the browser form. But when i try to add this option to a template it gives me NoReverseMatch. My template:
{% for manufacturer in manufacturer_list %}
<p>{{manufacturer.1}}</p>
{% endfor %}
It is my view:
class ItemListView(ListView):
model = Item
context_object_name = 'item_list'
template_name = 'shop/item_list.html'
def get_queryset(self, **kwargs):
full_item_list=Item.objects.all()
queryset=full_item_list.filter(category__id=int(self.kwargs['category_id']))
manufacturer_id = self.request.GET.get('manufacturer_id')
if manufacturer_id:
queryset=queryset.filter(manufacturer__id=int(manufacturer_id))
return queryset
def get_context_data(self, **kwargs):
context = super(ItemListView, self).get_context_data(**kwargs)
context['category']=get_object_or_404(Category, pk=self.kwargs['category_id'])
context['manufacturer_list'] = self.get_queryset(**kwargs).values_list('manufacturer__id', 'manufacturer__name').distinct().order_by('manufacturer__name')
return context
What is my mistake?

You didn't configure GET params... May be shop/category_6/?manufacturer_id=3
{{manufacturer.1 }}

Related

Django tables 2 - how do i change the queryset of the model i am displaying?

I'm trying to display all model objects after a get request in a table using django-tables2. It's currently displaying all and I can't figure out how to filter the queryset based on a model pk in my view:
views.py
class ViewJob(LoginRequiredMixin, SingleTableView):
model = JobResults
table_class = JobResultsTable
template_name = 'app/viewjobresults.html'
paginator_class = LazyPaginator
table_pagination = {"per_page": 30}
def get_context_data(self, **kwargs):
""" ViewJob get_context_data request """
context = super(ViewJob, self).get_context_data(**kwargs)
print("ViewJob >get_context_data()")
context['job_obj'] = Job.objects.get(pk=self.kwargs.get('pk'))
# context['object_list'] = context['object_list'].filter(job_id=context['job_obj'].id)
return context
template - app/viewjobresults.html
{% extends "base.html" %}
{% load render_table from django_tables2 %}
{% render_table table %}
{% endblock %}
tables.py
class JobResultsTable(tables.Table):
job = tables.Column(
accessor='job_id.job_name',
verbose_name='Job')
results = tables.Column(
accessor='results',
verbose_name='Result')
class Meta:
attrs = {"class": "table is-bordered"}
Currently the table rendered is ALL Job objects in a queryset. I have the specific job_obj in my view get_context_data() to filter this, but when i filter context['object_list'] (line hashed out) it still displays the entire list of JobResults. How can I change the queryset given to the table?
You can use the get_table_data() method to modify your queryset.
class ViewJob(LoginRequiredMixin, SingleTableView):
def get_table_data(self):
job_pk = self.request.GET.get('pk')
if job_pk:
return Job.objects.get(pk=job_pk)
else:
return Job.objects.all()
https://django-tables2.readthedocs.io/en/latest/pages/generic-mixins.html

Django sum of objects filtered by date view

I want to get sum of items i get by using generic date view.
Example views.py
class OrderDayArchiveView(LoginRequiredMixin, generic.dates.DayArchiveView):
queryset = Order.objects.all()
date_field = 'date_ordered'
template_name = 'ordersys/manager/archive_page.html'
Example template:
{% for order in object_list %}
<li class="bg-light">
{{ order.id }}: {{order.print_ordered_items_products_amounts}} (${{order.create_cost}})
</li>
{% endfor %}
Example path in urls.py:
path('<int:year>/<int:month>/<int:day>/', views.OrderDayArchiveView.as_view(month_format='%m'), name="archive_day"),
I want to get sum of all 'order.create_cost' sent to template, is it possible to get filtered queryset in this view? If not, how can i sum it in the template.
You can simply override get_context_data and add your aggregation there:
from django.db.models import Sum
class OrderDayArchiveView(LoginRequiredMixin, generic.dates.DayArchiveView):
queryset = Order.objects.all()
date_field = 'date_ordered'
template_name = 'ordersys/manager/archive_page.html'
def get_context_data(self, *, object_list=None, **kwargs):
context = super().get_context_data(object_list=object_list, **kwargs)
queryset = context['object_list']
sum_create_cost = queryset.aggregate(Sum('create_cost'))['create_cost__sum']
context['sum_create_cost'] = sum_create_cost
return context

Getting model name in Django template

I am trying to do a search over many data models in Django to my site.
Now I have code like this in views.
class Search(ListView):
template_name="search.html"
context_object_name="result_serch_all"
paginate_by = 10
def get_queryset(self):
news = Articles.objects.filter(title__icontains=self.request.GET.get("q"))
docs = Doc.objects.filter(name_doc__icontains=self.request.GET.get("q"))
query_sets = list(chain(news, docs))
return query_sets
def get_context_data(self, *args, **kwargs):
paginator = Paginator(self.get_queryset(), 5)
context = super().get_context_data(*args, **kwargs)
context["q"] =f'q={self.request.GET.get("q")}&'
print(context['result_serch_all'])
return context
In the template, I output like this
{%for el in result_serch_all%}
<div> {{el}} </div>
{% endfor %}
How can the output in the template be divided into blocks?So that in front of all found articles there is an inscription Found in the news section. Before the documents Found in the documents section`?
I found this option. In my model im add
def get_my_model_name(self):
return self._meta.model_name
and in the template I check
{% if el.get_my_model_name == 'articles' %}
Maybe there is some standard way in Django?

How to filter and paginate in ListView Django

I have a problem when I want to paginate the filter that I create with django_filter, in my template it shows me the query set and filter but paginate does not work, I would like to know why this happens and if you could help me.
I'll insert snippets of my code so you can see.
This is my views.py
PD: i have all the necesary imports.
#method_decorator(staff_member_required, name='dispatch')
class EmployeeListView(ListView):
model = Employee
paginate_by = 4
def dispatch(self, request, *args, **kwargs):
if not request.user.has_perm('employee.view_employee'):
return redirect(reverse_lazy('home'))
return super(EmployeeListView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = EmployeeFilter(self.request.GET, queryset = self.get_queryset())
return context
filters.py
import django_filters
from .models import Employee, Accident
class EmployeeFilter(django_filters.FilterSet):
class Meta:
model = Employee
fields = {
'rutEmployee' : ['startswith']
}
You should override get_queryset.This means you have to put your filter in get_queryset like this:
#method_decorator(staff_member_required, name='dispatch')
class EmployeeListView(ListView):
model = Employee
paginate_by = 4
def dispatch(self, request, *args, **kwargs):
if not request.user.has_perm('employee.view_employee'):
return redirect(reverse_lazy('home'))
return super(EmployeeListView, self).dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['filter'] = EmployeeFilter(self.request.GET, queryset = self.get_queryset())
return context
def get_queryset(self):
queryset = super().get_queryset()
return EmployeeFilter(self.request.GET, queryset=queryset).qs
and use object_list instead of filter in employee_list.html like this:
{% for employee in object_list|dictsort:"id" reversed %}
You could also try this:
(A snippet from my source code)
class ModelListView(ListView):
model = YourModel
paginate_by = 4 # Change this if you don't intend to paginate by 4
ordering = model_field_to_order_by
# variable used to know if a match was found for the search made using django_filters
no_search_result = False
def get_queryset(self, **kwargs):
search_results = YourDjangoFiltersForm(self.request.GET, self.queryset)
self.no_search_result = True if not search_results.qs else False
# Returns the default queryset if an empty queryset is returned by the django_filters
# You could as well return just the search result's queryset if you want to
return search_results.qs.distinct() or self.model.objects.all()
def get_query_string(self):
query_string = self.request.META.get("QUERY_STRING", "")
# Get all queries excluding pages from the request's meta
validated_query_string = "&".join([x for x in re.findall(
r"(\w*=\w{1,})", query_string) if not "page=" in x])
# Avoid passing the query path to template if no search result is found using the previous query
return "&" + validated_query_string.lower() if (validated_query_string and not self.no_search_result) else ""
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Pass to template if you want to do something whenever an empty queryset is return by django_filters
context["no_search_result"] = self.no_search_result
# This is the query string which should be appended to the current page in your template for pagination, very critical
context["query_string"] = self.get_query_string()
context['filter'] = YourDjangoFiltersForm()
return context
In your html template you need to append the querystring passed to your template from the view, a sample is shown below
{% for i in page_obj.paginator.page_range %}
{% if page_obj.number == i %}
<li class="page-item active" aria-current="page">
<span class="page-link">{{ i }}<span class="sr-only">(current)</span></span>
</li>
{% elif i > page_obj.number|add:'-5' and i < page_obj.number|add:'5' %} <li class="page-item"><a
class="page-link" href="?page={{ i }}{{ query_string }}">{{ i }}</a></li>
{% endif %}
{% endfor %}

Context is not displaying in the template when using ListView

I can't understand why nothing comes out in the html template.
class TrainersListView(ListView):
model = Profile
template_name = 'trainers.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
_list = Profile.objects.filter(city__slug=self.kwargs['slug']).order_by('id')
context['trainers'] = _list
print(len(context['trainers']) --> return 5
html
{% for trainer in trainers %}
{{ trainer.id }}
{% endfor %}
Even if I take out all the instances
_list = Profile.objects.all()
still a blank result
Am I doing everything right?
You forgot
return context
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
_list = Profile.objects.filter(city__slug=self.kwargs['slug']).order_by('id')
context['trainers'] = _list
print(len(context['trainers']) --> return 5
return context
Doc: Generic display views

Categories