I would like to count the number of "todo" in my ListView
views.py
class DashboardListView(LoginRequiredMixin,ListView):
model = Links
template_name = 'dashboard/home.html'
context_object_name ='links_list'
paginate_by = 15
def get_queryset(self):
return self.model.objects.filter(author=self.request.user)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['dashboard_list']= Dashboard.objects.filter(author=self.request.user)[:15]
context['todo_list']= Todo.objects.filter(author=self.request.user).order_by('-pk')[:15]
context['PasswordUsername_list']= PasswordUsername.objects.filter(author=self.request.user)
return context
And render it with {{c_count}} in my template but was unable to do so.
Thanks
Since you probably will render the list as well, using the length template filter [Django-doc] is probably the fastest way to do this, since it will fetch the objects, and calculate the length, so we can render this like:
{{ todo_list|length }}
If you are only interested in the length itself, and not in the objects of a todo_list, we can call .count() on the QuerySet, but this also has an extra disadvantage that it will only work for QuerySets (or classes that have a .count() method):
<!-- only interested in the count, not in the objects -->
{{ todo_list.count }}
Related
I'm looking to pass a list as the queryset parameter to a Django ListView. I know you can do this by overwriting the get_queryset method but ideally I would like to avoid this. The reason is, I am referring from another view and already have the queryset I need so I don't want to run the same query twice.
Currently I am linking to my view as follows:
{{active|length}
active is the prepopulated list I want to use as the queryset.
My view looks as follows:
class ProjectListOngoing(ListView):
template_name = "<name of my template>"
model = Project
context_object_name = "projects"
paginate_by = 10
def dispatch(self, request, *args, **kwargs):
self.projects = request.GET.get('projects', [])
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return self.projects
This does seem to populate the correct queryset however the primary keys are blank for some reason.
I have the following in my template:
{% for project in projects %}
<li></li>
{% endfor %}
And I get the following error:
Reverse for 'project_detail' with keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['project/(?P<pk>\\d+)/$']
I have this model:
class ModelName(models.Model):
def my_dict(self):
for i in range(n):
…#some code
context_a = {‘a’: a}
return context_a
I need to take context into view like this:
from .models import ModelName
class ViewName
model = ModelName
template_name = ’template_name.html’
def context_b(request):
context_b = ModelName.objects.get(context_a=context_a) #here I want to get context_a as a dictionary and pass it to context_b for further operations. I know that my syntax here is not correct.
return render(request, self.template_name, context_b)
If I do it, I get
Method Not Allowed: /
[18/Nov/2018 12:40:34] "GET / HTTP/1.1" 405 0
I would like to know how to do it correctly, and also which specific resource (documentation and/or article) should I read/learn to understand my problem.
I would appreciate any help.
I think you are not subclassing proper class based view here.
The error you are getting is that, you are calling get method, but the View you have provided does not support that. For simplistic purpose, lets use DetailsView which supports get request, so you can try like this:
class YourView(DetailsView):
template_name = 'template_name.html'
model = MyModel
def get_context_data(self, **kwargs):
context = super(YourView, self).get_context_data(**kwargs)
context_a = self.object.my_dict() # here you will get the dictionary from model in view
# by the way, you can also access the your model object from context via context['object'] and in template via {{ object }}
return context
And access dictionary of the template like this:
{% for k, v in object.my_dict.items %}
{{ k }} - {{ v }}
{% endfor %}
Also the Url
#urls
path('/someview/<int:pk>/', YourView.as_view(), name="your_view"),
I've overridden a detail view so I can render form elements with render_field. However, when rendered they do not show the saved values. I can't set the value in the template because I can't put {{}} within {% %} syntax. How can I access and display the previously saved model instance values? (these are sliders that I want to keep as sliders, and they also have a lot of data attributes that I want to keep consistent, so I can't just write the inputs manually in the template)
In views.py:
class MyDetailEditMixin(SingleObjectMixin):
"""
Hybrid mixin to edit a detail
"""
model = MyModel
form_class = forms.MyForm
raise_execption = True
def get_context_data(self, **kwargs):
"""
expose the form
"""
kwargs.setdefault('form', forms.MyForm)
return super(MyDetailEditMixin, self).get_context_data(**kwargs)
class MyDetailView(MyDetailEditMixin, DetailView):
"""
Shows the details
"""
I feel like I need to explicitly mention the instance somehow? I'm not sure. The inputs render correctly with all their specific data attributes, just no set values.
I tried many different things, but in the end I ditched the mixin and edited MyDetailView with a get_form method (and within that I could tell it to use the instance):
class MyDetailView(DetailView):
"""
Shows the details
"""
form_class = forms.MyForm
def get_form(self):
form = self.form_class(instance=self.object)
return form
def get_context_data(self, **kwargs):
context = super(MyDetailView, self).get_context_data(**kwargs)
context.update({
'form': self.form_class(instance=self.get_object()),
})
return context
The render_field fields have their values filled with the saved instance values and all the attributes they need are there.
I recently learned that you should override the get method when you specifically want to do something other than what the default view does:
class ExampleView(generic.ListView):
template_name = 'ppm/ppm.html'
def get(self, request):
manager = request.GET.get('manager', None)
if manager:
profiles_set = EmployeeProfile.objects.filter(manager=manager)
else:
profiles_set = EmployeeProfile.objects.all()
context = {
'profiles_set': profiles_set,
'title': 'Employee Profiles'
}
That's simple enough, but when should I use get_queryset or get_context_data over get? To me it seems like they basically do the same thing or am I just missing something? Can I use them together? This is a major source of confusion for me.
So to reiterate: In what cases would I use get over get_queryset or get_context_data and vise versa?
They indeed do different things.
get()
This is a top-level method, and there's one for each HTTP verb - get(), post(), patch(), etc. You would override it when you want to do something before a request is processed by the view, or after. But this is only called when a form view is loaded for the first time, not when the form is submitted. Basic example in the documentation. By default it will just render the configured template and return the HTML.
class MyView(TemplateView):
# ... other methods
def get(self, *args, **kwargs):
print('Processing GET request')
resp = super().get(*args, **kwargs)
print('Finished processing GET request')
return resp
get_queryset()
Used by ListViews - it determines the list of objects that you want to display. By default, it will just give you all for the model you specify. By overriding this method you can extend or completely replace this logic. Django documentation on the subject.
class FilteredAuthorView(ListView):
template_name = 'authors.html'
model = Author
def get_queryset(self):
# original qs
qs = super().get_queryset()
# filter by a variable captured from url, for example
return qs.filter(name__startswith=self.kwargs['name'])
get_context_data()
This method is used to populate a dictionary to use as the template context. For example, ListViews will populate the result from get_queryset() as author_list in the above example. You will probably be overriding this method most often to add things to display in your templates.
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
data['page_title'] = 'Authors'
return data
And then in your template, you can reference these variables.
<h1>{{ page_title }}</h1>
<ul>
{% for author in author_list %}
<li>{{ author.name }}</li>
{% endfor %}
</ul>
Now to answer your main question, the reason you have so many methods is to let you easily stick your custom logic with pin-point accuracy. It not only allows your code to be more readable and modular, but also more testable.
The documentation should explain everything. If still not enough, you may find the sources helpful as well. You'll see how everything is implemented with mixins which are only possible because everything is compartmentalized.
Let's look at the default implementation of ListView's get method:
https://github.com/django/django/blob/92053acbb9160862c3e743a99ed8ccff8d4f8fd6/django/views/generic/list.py#L158
class BaseListView(MultipleObjectMixin, View):
"""
A base view for displaying a list of objects.
"""
def get(self, request, *args, **kwargs):
self.object_list = self.get_queryset()
allow_empty = self.get_allow_empty()
if not allow_empty:
# When pagination is enabled and object_list is a queryset,
# it's better to do a cheap query than to load the unpaginated
# queryset in memory.
if (self.get_paginate_by(self.object_list) is not None
and hasattr(self.object_list, 'exists')):
is_empty = not self.object_list.exists()
else:
is_empty = len(self.object_list) == 0
if is_empty:
raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.")
% {'class_name': self.__class__.__name__})
context = self.get_context_data()
return self.render_to_response(context)
You will notice that get_queryset gets called in the first line. You can simply overwrite that if you just want to return your model's queryset after applying some filtering/ordering etc.
You don't need to overwrite the whole get method for that because you will be missing on all this provided functionality i.e. pagination, 404 checks etc.
get_context_data merges the resulting queryset together with context data like querystring parameters for pagination etc.
What I would recommend would be to check with django's source every once in a while and try to understand it a little bit so that you can recognize the most appropriate method you can overwrite/replace.
Here is what I have, a simple Django form
class survey (forms.Form):
answer = forms.ChoiceField(
widget = RadioSelect(),
choices = answers_select
)
Now, on my HTML page, I got not just one question but many! Is it possible to use the above answer field for all the questions? For all the questions, its just the same choices I have to show!
Say I have 3 questions:
How is my restaurant
How is the food
How is the service
choices for the above answer field are 1. good, 2. bad 3. worst
So, I don't want to create 3 form fields for the 3 questions as its redundant
Step back and think it clearly through--you'll need 3 ChoiceField to track the answer for 3 separate questions and there's no way around it.
What would be redundant is to actually repeat the form field construction call, especially if you were dealing with, say, 20 questions. In this case, rather than statically constructing those fields, you can store the list of questions as a class invariant and create the form fields dynamically during the forms construction.
Here's something to give you a starting idea on how you might go about doing it:
class SurveyForm(forms.Form):
questions = _create_questions('How is my restaurant?',
'How is the Food?',
'How is the service?')
def __init__(self, *args, **kwargs):
# Create the form as usual
super(SurveyForm, self).__init__(*args, **kwargs)
# Add custom form fields dynamically
for question in questions:
self.fields[question[0]] = forms.ChoiceField(label=question[1],
widget=forms.RadioSelect(),
choices=answers_select)
#classmethod
def _create_questions(cls, *questions):
return [(str(index), question) for index, question in enumerate(questions)]
You're looking for formsets. You could do something like this:
from django.forms.formsets import formset_factory
SurveyFormSet = formset_factory(survey, extra=3, max_num=3)
Add it to your context:
def get_context_data(self, request, *args, **kwargs):
data = super(MyView, self).get_context_data(request, *args, **kwargs)
data['formset'] = SurveyFormSet()
return data
Then use it in the template:
<form method="post" action="">
{{ formset.management_form }}
<table>
{% for form in formset %}
{{ form }}
{% endfor %}
</table>
</form>
During a post, you'll want to pass request.POST and request.FILES into the formset constructor:
formset = SurveyFormSet(request.POST, request.FILES)
It's all described pretty thoroughly in that linked documentation.