django template print only first unique occurance - django

I have a pretty simple task to do but I do not know how to do it most effectively in django templates.
Basically, this is what I am trying to accomplish:
Jan. 27, 2015
first post
second post
third post
Jan. 28, 2015
another post
and other
etc
Feb. 18, 2015
again
and again
This could be its model:
class Post(models.Model):
date=models.DateField()
name=models.CharField()
In views.py passing just queryset as posts:
Post.objects.filter(date__gte = date.today()).order_by("date")
And then in template priting it out with for cycle:
{% for post in posts%}
{{post.name}}
{% endfor %}
How do I get printed unique date only once? Is it possible to do this in templates or do I have to take care of it in views? I found similar two year old post.

There is an inbuilt template tag for that - regroup!
This isn't perfect, but with the documentation it should get you close.
{% regroup posts by date as date_list %}
<ul>
{% for date in date_list %}
<li>{{ date.grouper }}
<ul>
{% for item in date.list %}
<li>{{ date.name }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>

You can use {% ifchanged %} template tag:
{% for post in posts %}
{% ifchanged %}<h3>{{ post.date }}</h3>{% endifchanged %}
<div>{{ post.name }}</div>
{% endfor %}

Related

How to pass a date (year) parameter to my url?

This is a huge rookie mistake but I can't figure it out.
This is what I wanna do:
I have a page displaying a list a years where an objects is available.
I want that, when I click on a year, it takes me to the corresponding YearArchiveView. I just don't succeed in passing the right parameter to the URL. Passing a template tag obviously doesnt work so what is the right way to do it ?
I get this error:
TemplateSyntaxError at /receipts/
Could not parse some characters: |{{y||date:"Y"}}
My template:
<ul>
{% for y in years_available %}
<li>{{y|date:"Y"}}</li>
{% empty %}
<p>No Receipt Yet</p>
{% endfor %}
</ul>
My view:
class ReceiptListView(LoginRequiredMixin, ListView):
model = Receipt
template_name = 'receipts.html'
def get_queryset(self):
queryset = Receipt.objects.dates('date_created','year',order="DESC")
return queryset
def get_context_data(self, *args, **kwargs):
context = super(ReceiptListView, self).get_context_data(**kwargs)
context['years_available'] = Receipt.objects.dates('date_created',
'year', order="DESC")
return context
My urls.py:
url(r'receipts/(?P<year>[0-9]{4}/$)',views.ReceiptYearArchiveView.as_view(),
name='receipt_year_archive'),
you dont need year=
just use this
<ul>
{% for y in years_available %}
{% with y|date:"Y" as current_year %}
<li>{{y|date:"Y"}}</li>
{% endwith %}
{% empty %}
<p>No Receipt Yet</p>
{% endfor %}
</ul>
You can't add another {{ and }} inside {%. It should call with direct variable.
<ul>
{% for y in years_available %}
<li>{{ y|date:"Y" }}</li>
{% empty %}
<p>No Receipt Yet</p>
{% endfor %}
</ul>
But, I think your case similiar with this docs examples:
<ul>
{% for yearvar in year_list %}
<li>{{ yearvar }} Archive</li>
{% endfor %}
</ul>
If the output of years_available is a list of integer years.
eg: [1992, 2001, 2005, 2011, 2014]
It should be:
<ul>
{% for y in years_available %}
<li>{{ y }}</li>
{% empty %}
<p>No Receipt Yet</p>
{% endfor %}
</ul>

Django Stopping loop after x times within a template

I have queryset that returns many records but in the template I use it twice to return value.
For example:
On one instance I need to return the latest 5 posts and then show all the posts on that same page. So for that reason I can't use LIMIT in my queryset.
{% for post in blog_posts %}
<li>{{ post.title }}</li>
{% endfor %}
From that example how can I stop to loop after 5 times.
Use the slice filter:
{% for post in blog_posts|slice:":5" %}
<li>{{ post.title }}</li>
{% endfor %}

work around setting variables in django templates

I have this code that I used from twig to display sections according to the same date.
I'm trying to use the same code in Django but I can't set variables in its template system. What is the sane way to do this? The correct way? How do people tackle such a problem?
{% set date = "prout" %}
{% for article in articles %}
{% if article.date != date %}
{% if date != "prout" %}
</ul>
</section>
{% endif %}
{% set date = article.date %}
<section class="row">
<h2>{{ article.date }}</h2>
<ul>
<li>+ {{ article.titre }}</li>
{% else %}
<li>+ {{ article.titre }}</li>
{% endif %}
{% endfor %}
</ul>
</section>
The closer concept to 'set' variables is with tag. Quoting Built-in template tags and filters django docs:
with
Caches a complex variable under a simpler name. This is useful
when accessing an “expensive” method (e.g., one that hits the
database) multiple times.
For example:
{% with total=business.employees.count %}
{{ total }} employee{{ total|pluralize }}
{% endwith %}

Using custom object manager on related set

Im trying to print out 4 entries. It works, as long I don't have any entries not published.
How can I get a queryset that only contains objects from my "published" manager?
Now I use: {% if benefit.status == "p" %} to not print those entries not published, but then the unpublished effects the slice count.
#views.py:
class PackageListFrontpage(ListView):
context_object_name = "package_frontpage_list"
template_name = "frontpage.html"
queryset = Package.published.all().order_by('order')[:5]
#frontpage.html
{% for package in package_frontpage_list %}
<div>
<h3>{{ package.name }} >></h3>
<ul>
{% for benefit in package.benefit_set.all|slice:":4" %}
{% if benefit.status == "p" %}
<li>{{ benefit.name }}</li>
{% endif %}
{% empty %}
<li>There are no published benefits in this package</li>
{% endfor %}
</ul>
</div>
{% endfor %}
I guess there is a better way of doing this?
You could define a method on your Package model that returns the queryset of related benefits which are published.
class Package(object):
...
def benefit_set_published(self):
"""
Return the related benefits which are published
"""
return self.benefit_set.filter(status="p")
Then change your template to:
{% for benefit in package.benefit_set_published.all|slice:":4" %}
<li>{{ benefit.name }}</li>
{% empty %}
<li>There are no published benefits in this package</li>
{% endfor %}

Rename grouper in regroup

I have read this, but I have one more question: how I can rename country.grouper in the template? I 'group' week days - week_days.grouper, its like 1, 2, 3 etc. But I want change it in the template - Sunday, Monday etc. How to do it?
A custom template tag should help you out here. It has to be put into a file e.g. my_custom_filters.py in your app in a folder called templatetags:
from django import template
register = template.Library()
def get_weekday(value):
"""returns the weekday for the given number - 0 indexed"""
wd_list = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]
return wd_list[int(value)]
This custom filter will be used like this:
{% load my_custom_filters %}
{% regroup day by weekdays as weekday_list %}
<ul>
{% for day in weekday_list %}
<li>{{ day.grouper|get_weekday }}
<ul>
{% for item in day.list %}
<li>{{ item.name }}: {{ item.population }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
If you are using a date object could use the build-in date template tag to convert a date to the corresponding weekday:
{% regroup day by weekdays as weekday_list %}
<ul>
{% for day in weekday_list %}
<li>{{ day.grouper|date:"w" }}
<ul>
{% for item in day.list %}
<li>{{ item.name }}: {{ item.population }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>