Context is not displaying in the template when using ListView - python

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

Related

Can you have two get_context_data functions in a single django view?

I have a home view, along with a TagFilter view using django-taggit:
class Home(ListView):
model = Group
template_name = 'home.html'
ordering = ['-posted']
def get_tags(self):
tags = Tag.objects.all()
return tags
def get_common_tags(self):
common_tags = Group.tags.most_common()[:2]
return common_tags
def get_context_data(self, **kwargs):
kwargs['common_tags'] = self.get_common_tags()
return super().get_context_data(**kwargs)
class TagFilter(ListView):
model = Group
template_name = 'home.html'
context_object_name = 'groups'
def get_common_tags(self):
common_tags = Group.tags.most_common()[:2]
return common_tags
def get_context_data(self, **kwargs):
kwargs['common_tags'] = self.get_common_tags()
return super().get_context_data(**kwargs)
def get_queryset(self):
tag_list = Group.objects.filter(tags__slug=self.kwargs.get('tag_slug'))
return tag_list
def get_context_data(self, *args, **kwargs):
tag_list = Group.objects.filter(tags__slug=self.kwargs.get('tag_slug'))
tag_list_is_empty = True
if tag_list.exists():
tag_list_is_empty = False
context = super(TagFilter, self).get_context_data()
context["tag_list_is_empty"] = tag_list_is_empty
return context
The reason I put:
def get_common_tags(self):
common_tags = Group.tags.most_common()[:2]
return common_tags
def get_context_data(self, **kwargs):
kwargs['common_tags'] = self.get_common_tags()
return super().get_context_data(**kwargs)
In both views is that common_tags wouldn't show up on the home url if it was only in TagFilter and vice versa (i.e., group/<int:pk>/slug/ if it was only in the home view.
My issue is I can't have my cake and eat it too. Either I have common_tags in only one view or I get it in both views but can't access tag_list_is_empty. When I try and combine both into one function using context the same thing is happening.
This leads me to think you can't have a multiple get_context_data functions in one view. Or that you can't return multiple variables using context in general.
Here's my template where I'm rendering both tag lists:
<div>Filter by tag:
{% for tag in tags %}
#{{tag.name}}
{% endfor %}
</div>
<div>Common tags:
{% for tag in common_tags %}
#{{tag.name}}
{% endfor %}
</div>

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 %}

Django: How to implement request.session in a class based view

I have a hard time understanding class based views in Django. At this time I try to implement a request.session in a ListView. I try to implement the following function based code from the MdM Django Tutorial in to a ListView.
def index(request):
...
# Number of visits to this view, as counted in the session variable.
num_visits = request.session.get('num_visits', 0)
request.session['num_visits'] = num_visits + 1
context = {
'num_visits': num_visits,
}
return render(request, 'index.html', context=context)
I tried the following (and a lot of other things) but to no avail:
class ListPageView(FormMixin, ListView):
template_name = 'property_list.html'
model = Property
form_class = PropertyForm
def get(self, request, *args, **kwargs):
num_visits = request.session.get('num_visits', 0)
request.session['num_visits'] = num_visits + 1
return super().get(request, *args, **kwargs)
# ... some more code here
In my template I have:
<p>You have visited this page {{ num_visits }}{% if num_visits == 1 %} time{% else %} times{% endif %}.</p>
But the template variable renders always empty.
You still need to pass it to the context, by overriding the get_context_data method [Django-doc]:
class ListPageView(FormMixin, ListView):
template_name = 'property_list.html'
model = Property
form_class = PropertyForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['num_visits'] = self.request.session['num_visits']
return context
def get(self, request, *args, **kwargs):
num_visits = request.session.get('num_visits', 0)
request.session['num_visits'] = num_visits + 1
return super().get(request, *args, **kwargs)
I understand that this is a late answer, but I ran into the same problem, and I will try to put my two cents in and maybe my answer will help newbies like me.
Your template always has access to the {{ request }} variable, so you can simply use {{request.session.key}} without defining additional context.
I can also see that you used the {% if %} conditional for the plural, but Django has a nice filter {{ value|pluralize }}, it might be more useful for that.

Setting GET parameters in url in Django

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 }}

Django Wizard, multiple forms in one step

In documentation of Django Wizard i found code like this:
{{ wizard.management_form }}
{% if wizard.form.forms %}
{{ wizard.form.management_form }}
{% for form in wizard.form.forms %}
{{ form }}
{% endfor %}
{% else %}
{{ wizard.form }}
{% endif %}
So I am wondering how can i add multiple forms to single step of wizard
Make one of your forms a Formset containing the rest of the forms you need. You don't need to necessarily use a ModelFormset, you can subclass the base class and create the forms manually.
This is now deprecated use this link: https://github.com/vikingco/django-formtools-addons
I wanted to share my settings if would be any help to anyone:
class BaseImageFormSet(BaseModelFormSet):
def __init__(self, *args, **kwargs):
super(BaseImageFormSet, self).__init__(*args, **kwargs)
self.queryset = Images.objects.none()
ImageFormSets = modelformset_factory(Images, formset=BaseImageFormSet, fields=('picture',), extra=2)
form_list = [("step1", CategoryForm),
("step2", CityForm),
("step3", (
('lastform', LastForm),
('imageform', ImageFormSets)
))
]
templates = {"step1": "create_post_category.html",
"step2": "create_post_city.html",
"step3": "create_post_final.html"}
class OrderWizard(SessionMultipleFormWizardView):
file_storage = FileSystemStorage(location=os.path.join(settings.MEDIA_ROOT, 'photos'))
def get_template_names(self):
return [templates[self.steps.current]]
def render(self, forms=None, **kwargs):
forms = forms or self.get_forms()
context = self.get_context_data(forms=forms, **kwargs)
#print(forms[1](queryset = Images.objects.none()))
return self.render_to_response(context)
def done(self, form_list, form_dict, **kwargs):
form_data_dict = self.get_all_cleaned_data()
#print(form_data_dict)
result = {}
instance = Post()
#print(form_dict)
for key in form_dict:
form_collection = form_dict[key]
#print(form_collection)
for key in form_collection:
form = form_collection[key]
print('printing form %s' % key)
#if isinstance(form, forms.ModelForm):
if key == 'lastform':
post_instance = form.save(commit=False)
nodes = form_data_dict.pop('nodes')
city = form_data_dict.pop('city')
post_instance.save()
post_instance.category.add(nodes)
post_instance.location.add(city)
print('lastfome as esu ')
if key == 'imageform':
for i in form_data_dict['formset-step3']:
picture = i.pop('picture')
images_instance = Images(post=post_instance, picture=picture)
images_instance.save()
return render_to_response('create_post_done.html', {
'form_data': result,
#'form_list': [form.cleaned_data for form in form_list],
})
I've implemented an extension to the Django Wizard, which supports multiple Forms in one wizard step:
https://pypi.python.org/pypi/django-multipleformwizard

Categories