Django version: 1.11.3
I have stored data in a sqlite database as I want to have displayed in a pdf. I use easy-pdf. I don't know how to parse the data without using render(). How do I do it with get_context_data(). Any suggestions?
This works:
def test(request):
all_organizations = Organization.objects.all()
all_tickets = Ticket.objects.all()
context = {'all_organizations': all_organizations, 'all_tickets': all_tickets}
return render(request, 'test/docs/examples/theme/test.html', context)
Don't know how to parse all_organizations and all_tickets for use in the easy-pdf:
class HelloPDFView(PDFTemplateView):
all_organizations = Organization.objects.all()
all_tickets = Ticket.objects.all()
context = {'all_organizations': all_organizations, 'all_tickets': all_tickets}
template_name = "test/docs/examples/theme/hello.html"
def get_context_data(self, **kwargs):
return super(HelloPDFView, self).get_context_data(
pagesize="A4",
title="Test",
**kwargs
)
def get_context_data(self, **kwargs):
context = super(HelloPDFView, self).get_context_data(**kwargs)
context['all_organizations'] = Organization.objects.all()
context['all_tickets'] = Ticket.objects.all()
context['pagesize']="A4"
context['title']= 'Test'
return context
try this, and in the template you can access the data using the key names like pagesize, title and all
Related
I need to pass a Tag object to the template, but without an additional query to the database in get_context_data method.
Can you please tell me if there is a more elegant way to get the value from the get_queryset method in the get_context_data.
And if there is a more elegant way, is it correct to declare your own fields in Django views
class PostListView(ListView):
model = Post
paginate_by = 3
context_object_name = 'posts'
template_name = 'blog/post/list.html'
tag = None
def get_queryset(self):
data = super().get_queryset()
if tag_slug := self.kwargs.get('tag_slug'):
self.tag = get_object_or_404(Tag, slug=tag_slug)
data = data.filter(tags__in=[self.tag])
return data
def get_context_data(self, *, object_list=None, **kwargs):
data = super().get_context_data(**kwargs)
data['tag'] = self.tag
return data
get queryset should only prepare queryset without any hit in database. In your case you do many not needed things:
def get_queryset(self):
query = Q()
if self.kwargs.get('tag_slug'):
query = Q(tags__slug=self.kwargs['tag_slug'])
return super().get_queryset().filter(query).select_related('tag')
in reality function above is One-liner.
You don't need any tag in context, but if you want:
def get_context_data(self, *args, **kwargs):
response = super().get_context_data(*args, **kwargs)
if len(response['object_list']) : # only one hit in database
response['tag'] = response['object_list'][0].tag
else:
raise Http404
return response
len made ask in database, and get all objects.
Based on reply I edit my code for the following:
because I need tag name and it can be different from tug slug I override get method to get tag object and not execute uselees code later
removed query from get_queryset
replaced "object_list" with "posts" due to iterating through posts in my template
class PostListView(ListView):
model = Post
paginate_by = 3
context_object_name = 'posts'
template_name = 'blog/post/list.html'
tag = None
def get(self, request, *args, **kwargs):
if tag_slug := self.kwargs.get('tag_slug'):
self.tag = get_object_or_404(Tag, slug=tag_slug)
return super(PostListView, self).get(request, *args, **kwargs)
def get_queryset(self):
query = Q()
if self.tag:
query = Q(tags__slug=self.tag)
return super(PostListView, self).get_queryset().filter(query)
def get_context_data(self, *args, **kwargs):
response = super().get_context_data(*args, **kwargs)
if len(response['posts']):
response['tag'] = self.tag
else:
raise Http404
return response
I have this class that changes user password:
class PasswordsChangeView(PasswordChangeView):
from_class = PasswordChangingForm
success_url = reverse_lazy(
"base:password/passwordsuccess",
)
And I would like to insert User Avatar Img Path in context.
This Img is inside a UserComplement model.
When I create function views, it works doing:
#login_required
def password_success(request):
try:
obg = UserComplement.objects.get(pk=request.user.id)
context = {
"img_avatar": obg.avatar_image,
}
return render(request, "registration/passwordsuccess.html", context)
except UserComplement.DoesNotExist:
return render(request, "registration/passwordsuccess.html")
The problem is that I cannot get the userID in classviews to pass it through the context on success_url.
It was a lack of knowledge on how class based views work. The function get_context_data did the job well, returning the context.
class PasswordsChangeView(PasswordChangeView):
from_class = PasswordChangingForm
success_url = reverse_lazy(
"base:password/passwordsuccess",
)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
obj = UserComplement.objects.get(pk=self.request.user.id)
context["img_avatar"] = obj.avatar_image
return context
I'm trying to print using wkhtmltopdf with a queryset from a django-filters filtered listview.
I can't use post because my list.html template is not a form.
filter_set = []
class IssueListView(TemplateListView):
def get_context_data(self, **kwargs):
context = super(IssueListView, self).get_context_data(**kwargs)
global filter_set
filter_set = []
for issue in context['object_list']:
filter_set.append(issue.pk)
return context
class IssuePDF(ReportTemplateView):
report_title = 'Complaints Register'
model = Issue
object_list = Issue.objects.all()
def get_context_data(self, **kwargs):
context = super(IssuePDF, self).get_context_data(**kwargs)
context['report_title'] = self.report_title
context['object_list'] = self.model.objects.all()
global filter_set
context['object_list'] = Issue.objects.filter(pk__in=filter_set)
return context
This works because I am currently using a global variable but the queryset changes everytime I print in the Production Server.
There are 2 ways to achieve that.
One is to store in session, like this:
class IssueListView(TemplateListView):
def get_context_data(self, **kwargs):
context = super(IssueListView, self).get_context_data(**kwargs)
self.request.session['filter_set'] = list(context['object_list'].values_list('pk', flat=True)) # This can be done get_queryset method as well
return context
And use it in IssuePDF:
class IssuePDF(ReportTemplateView):
report_title = 'Complaints Register'
model = Issue
object_list = Issue.objects.all()
def get_context_data(self, **kwargs):
context = super(IssuePDF, self).get_context_data(**kwargs)
context['report_title'] = self.report_title
filter_set = self.request.session.get('filter_set', None)
if filter_set:
context['object_list'] = Issue.objects.filter(pk__in=filter_set)
return context
Another way of achieving it is to pass the context as get parameter. Like this:
class IssueListView(TemplateListView):
def get_context_data(self, **kwargs):
context = super(IssueListView, self).get_context_data(**kwargs)
context['filter_set'] = list(context['object_list'].values_list('pk', flat=True))
return context
In template, update the print button/link like this:
<a href="{url 'app_name:print_view_url_name'}?filter_set={{ filter_set }}"
And use it in IssuePDF like this:
class IssuePDF(ReportTemplateView):
report_title = 'Complaints Register'
model = Issue
object_list = Issue.objects.all()
def get_context_data(self, **kwargs):
context = super(IssuePDF, self).get_context_data(**kwargs)
context['report_title'] = self.report_title
filter_set = self.request.GET.get('filter_set', None)
if filter_set:
context['object_list'] = Issue.objects.filter(pk__in=filter_set)
return context
I have the following class based view that I want to use to render a formset and validate it when it gets submitted through a post method:
The formset renders perfectly. When I submit the form I can read the formset and check it for errors. in the post method of this class -> errors = backorder_formset.errors
If I find any errors in the formset, I would like to render the view, but this time with the formset instance, that I read from POST.
When I call ctx = self.get_context_data() form within the post method of the class the following error gets raised from the call super(MissingProductsListView, self).get_context_data(*args, **kwargs):
'MissingProductsListView' object has no attribute 'object_list'
It seems like the superclass of Listview performs this call:queryset = kwargs.pop('object_list', self.object_list)
My question is why am I running in this error? and how could I render this formset with its errors messages to display it in the template after it was posted? I am using Django 1.9.9
class MissingProductsListView(generic.ListView):
template_name = 'dashboard/purchaseorder/missing_products.html'
context_object_name = 'backorders'
model = BackOrder
def post(self, request, *args, **kwargs):
backorder_formset = BackOrderFormset(request.POST)
errors = backorder_formset.errors
if backorder_formset.is_valid():
# <process form cleaned data>
return HttpResponseRedirect('/success/')
else:
ctx = self.get_context_data()
return self.render_to_response(ctx)
def accumulate_identical_products_from_backorders(self, back_order_list):
... some code
return sorted_accumulated_dict.values()
def get_context_data(self, *args, **kwargs):
ctx = super(MissingProductsListView, self).get_context_data(*args, **kwargs)
ctx['title'] = _("Missing Products")
if self.request.POST:
ctx['back_order_formset'] = BackOrderFormset(self.request.POST)
else:
accumulated_backorders_per_product = self.accumulate_identical_products_from_backorders(BackOrder.objects.all())
back_orders = BackOrderFormset(initial=[{'product_id': backorder_dict['product_id'],
'product': backorder_dict['title'],
'quantity': backorder_dict['quantity']} for backorder_dict in
accumulated_backorders_per_product])
ctx['back_order_formset'] = back_orders
return ctx
def get_queryset(self):
.. some code
return backorder_list
Look here:
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)
Basically - you missed this part in the POST handler:
self.object_list = self.get_queryset()
And to be honest - I am not quite sure if this is a good idea to add post to the generic ListView in django. It looks more like FormView - but I can be wrong here.
How do I write a DetailView in Django, that has other related Queries?
Here is my example:
class DistributionDetailView(DetailView):
model = Distribution
template_name = 'projects/view_distribution.html'
def get_context_data(self, **kwargs):
context = super(DistributionDetailView,
self).get_context_data(**kwargs)
context['weekly_attendance'] = WeeklyAttendance.objects.filter(
distibution_name=Distribution)
context['sales_data'] = SalesData.objects.filter(
distibution_name=Distribution)
context['theatrical_release'] = TheatricalRelease.objects.filter(
distibution_name=Distribution)
return context
Distribution is the model class, you can't use it inside filter(). In the get_context_data method, you can access the current object with self.object, for example:
context['weekly_attendance'] = WeeklyAttendance.objects.filter(
distibution_name=self.object)
You can access the object with self.object in most generic views:
class DistributionDetailView(DetailView):
model = Distribution
template_name = 'projects/view_distribution.html'
def get_context_data(self, **kwargs):
context = super(DistributionDetailView,
self).get_context_data(**kwargs)
context['weekly_attendance'] = WeeklyAttendance.objects.filter(
distibution=self.object)
context['sales_data'] = SalesData.objects.filter(
distibution=self.object)
context['theatrical_release'] = TheatricalRelease.objects.filter(
distibution=self.object)
return context