django - 2 views in one template - django-views

i have 2 different views which are getting filtered data from db. and i have to use these views in one template file(admin.html) but i cant use multiple views on a page at same time.
here is my view1:
draft_list = Post.objects.filter(isdraft=True).order_by("-posted")
return render_to_response('userside/admin.html',
{'draft_list':draft_list,},
context_instance = RequestContext(request))
view2 :
publish_list = Post.objects.filter(isdraft=False).order_by("-posted")
return render_to_response('userside/admin.html',
{'publish_list':publish_list,},
context_instance = RequestContext(request))
i d like to use them like :
{% for d in draft_list %}
{{ d.title }}
{% endfor %}
--
{% for p in publish_list %}
{{ p.title }}
{% endfor %}
i want to make these 2 views 'one view' .what is the correct way?

You do not want to have 2 views in 1 template (which is not possible anyway), but have 2 models available in 1 template for rendering. Just do it like this:
draft_list = Post.objects.filter(isdraft=True).order_by("-posted")
publish_list = Post.objects.filter(isdraft=False).order_by("-posted")
return render_to_response('userside/admin.html',
{'draft_list':draft_list,'publish_list':publish_list})

From your question, it seems that you're using function based views. An alternative way to solve the problem you're having is to use class based views and override the get_context_data method to pass your template two contexts, one for each queryset.
#views.py
class MyClassBasedView(DetailView):
context_object_name = 'draft_list'
template='my-template'
queryset = Post.objects.filter(isdraft=True).order_by("-posted")
def get_context_data(self, **kwargs):
context = super(MyClassBasedView, self).get_context_data(**kwargs)
context['publish_list'] = Post.objects.filter(isdraft=False).order_by("-posted")
return context

Related

Django Annotations - More efficient way?

In a class Based ListView I want to annotate each Post with the number of comments (this method works)
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['approved_comments'] = Comment.objects.values('post_id').annotate(c_count=Count('post_id')).filter(approved=True)
return context
in my Template I do the following (which feels really inefficient)
{% for comment in approved_comments %}
{% if post.id == comment.post_id %}
{{comment.c_count}}
{% endif %}
{% endfor %}
This gets me the result I want but I'm struggling to find a better way to deliver this since this seems really redundant.
I was trying to find a SO question that already deals with this but haven't found one so if you could point me to the link that would be helpful.
Thanks in advance :)
This is a quadratic JOIN, you should not do that. You can simply annotate the Posts with the number of approved comments in the view:
from django.db.models import Count, Q
from django.views.generic import ListView
class MyListView(ListView):
model = Post
queryset = Post.objects.annotate(
napproved_comments=Count('comment', filter=Q(comment__approved=True))
)
and then render this in the template with:
{{ post.napproved_comments }}

Generate PDF with Django Class Based Views

I currently have a Library Loan template implemented using Class Based Views. The implementation is probably something that we have seen before:
In urls.py:
#PK is the member ID
url(r'^library/generate_loan_slip/(?P<pk>(\d+))/(?P<loan>(\d+))/'
,LoanSlipDetailView.as_view()
, name='library_app_generate_loan_slip'),
In views.py:
class LoanSlipDetailView(DetailView):
model = LibraryMember
loan = None
template_name = 'loan-slip.html'
def get_context_data(self, **kwargs):
context['loan'] = self.loan
context['member'] = member
return context
def get_object(self):
member = self.model.objects.get(pk=self.kwargs['pk'])
self.loan = LibraryLoan.objects.get(pk=self.kwargs['loan'], for_member=member)
return member
And in the HTML, loan-slip.html, the html with all the required variables in {{}} and controls using {% if %} ... {% else %} ... {% endif %} and {% for ... %} ... {% endfor %}.
Right now, I want the response to generate a PDF view. So far, I have checked out reportlab and they implemented it for function based views. However, is there an implementation for Class Based Views?
You can just override get method of DetailView and write reportlab logic over there.

How to pass two or more objects from views for render it in template

Im working on Django, i need pass two or more objects to a view, for render it in the template. I mean,
i have one object, and this object can has two or more objects from other model, in the view i have:
def infoUsuario(request,id_usuario):
user = info_productor_cultivador.objects.get(id=id_usuario)
familiar = grupo_familiar.objects.filter(familiar_de_id=user)
ctx = {'usuario':user,'familiar':familiar}
return render_to_response('usuarios.html',ctx,context_instance=RequestContext(request))
in the template:
{% for familiares in familiar %}
<p>{{familiar.primer_nombre}}</p>
{% endfor %}
The models:
class grupo_familiar(models.Model):
familiar_de = models.ForeignKey(info_productor_cultivador)
primer_nombre = models.CharField(max_length=50)
class info_productor_cultivador(models.Model):
primer_nombre = models.CharField(max_length=50)
First, instead "filter" in familiar object i has "get" but said me: "get() returned more than one grupo_familiar -- it returned 2!" looking for a solution i found it that i have to pass the "filter" query, this time i dont have errors from Django, but the "familiar" object does not render it in the template.
In other words, i think that i need is how to pass a foreign key in the view and render it in the template.
Thanks
views
from django.shortcuts import render
def info_usuario(request, id_usuario):
user = info_productor_cultivador.objects.get(id=id_usuario)
familiar = grupo_familiar.objects.filter(familiar_de_id=user)
ctx = { 'usuario': user, 'familiar': familiar }
return render(request, 'usuarios.html', ctx }
template
{% for familiares in familiar %}
<p>{{ familiar.primer_nombre }}</p>
{% endfor %}

How to add extra data to a Django model for display in template?

My Django Model:
class myModel(models.Model):
myIntA = models.IntegerField(default=0)
My View:
myModelList = myModel.objects.all()
for i in range(len(myModelList)):
myModelList[i].myIntB = i
return render(
request,
'myApp/myTemplate.html',
Context(
{
"myModels": myModelList,
}
)
)
Is the above legal? You can see that I added a variable myIntB to each myModel object.
However when I try to print myIntB in the template below, nothing shows up.
How can I access myIntB from the template? It is not a field I have defined for this model, nor do I want it to be. I just want myModel to be augmented with this extra variable during rendering of this particular template.
My Template:
{% for currModel in myModels %}
{{currModel.myIntA}}<br/>
{{currModel.myIntB}}<br/>
{% endfor %}
Replace following line:
myModelList = myModel.objects.all()
with:
myModelList = list(myModel.objects.all())
Otherwise, new queries are performed everytime you access myModelList[i]; you lose the change you made.
Alternatively, what you want is simply counter, you can use forloop.counter or forloop.counter0 in the template.
No that won't do what you are thinking; try this instead:
enriched_models = []
myModelList = myModel.objects.all()
for i in myModelList:
enriched_models.append((i, 'foo'))
return render(request, 'myApp/myTemplate.html', {"myModels": enriched_models})
Then in your template:
{% for currModel,extra in myModels %}
{{ currModel.myIntA }}<br/>
{{ extra }}<br/>
{% endfor %}

Django ListView: taking a time difference in all items

I'm rather new to Class Based Views, so this is probably obvious, but any tips are appreciated. I want to display "time left" for each item on a list. That is if I have 10 objects, each should display in the template the number of days, hours, mn left until a deadline arrives. Here's my attempt:
model.py
class Law(models.Model):
deadline = models.DateTimeField(_(u'The Deadline'),)
name = ..
more_stuff = ..
views.py
class LawList(ListView):
model = Law
context_object_name = 'law'
template_name = 'template.html'
template.html
{% for l in law %}
<h3>{{ l.deadline }} - {{l.name }} </h3>
{{l.more_stuff}}
{% endfor %}
all good up to here. However I would like to have {{l.time-left}} instead of {{l.deadline}}. Is there a way for the view to calculate this and pass it to the template?
I thought of adding a get_context_data to the 'LawList' view, but I don't know how to do so for every item in my list. Below is what works for a single item.
# views.py, below the section above
def get_context_data(self, **kwargs):
context = super(LawList, self).get_context_data(**kwargs)
context['time_left'] = Law.objects.all()[0].deadline - timezone.now()
but I'm a little stuck. Thanks!
have a look at the timeuntil template tag