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

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>

Related

RoutablePageMixin and breadcrumbs

A standard Wagtail breadcrumb system like this works perfectly if all of your pages are in a tree (parents/children):
{% block main %}
{% if self.get_ancestors|length > 1 %}
<ul class="breadcrumb">
{% for page in self.get_ancestors %}
{% if page.is_root == False and page.url != '/' %}
<li>{{ page.title }}</li>
{% endif %}
{% endfor %}
<li class="active">{{ self.title }}</li>
</ul>
{% endif %}
{% endblock main %}
But it falls down if some of your sub-pages are not actual children, but instead use RoutablePageMixin. Because the routable pages are really different instances of the parent, the breadcrumb trail stops short of making it down to the routable page.
I thought I could add some extra info to the context to detect the situation and special-case it, but all of the WT URL methods return the URL of the "parent" page (i.e. the actual instance), and besides there is no programmatic "title" that could be used in the breadcrumb.
What's the best way to have a breadcrumb system that works equally well for child pages and routable pages?
Answering my own question (Thanks Robert for the hint). In the route definition in the model, add something like:
ctx['routed_title'] = 'Staff'
Then modify the breadcrumb example above like this (check for existence of the new element on context and append to breadcrumbs):
{% block main %}
{% if self.get_ancestors|length > 1 %}
<ul class="breadcrumb">
{% for page in self.get_ancestors %}
{% if page.is_root == False and page.url != '/' %}
<li>{{ page.title }}</li>
{% endif %}
{% endfor %}
{# If this is a routable, add non-parent/child link from context #}
{% if routed_title %}
<li>{{ page.title }}</li>
<li class="active">{{ routed_title }}</li>
{% else %}
<li class="active">{{ self.title }}</li>
{% endif %}
</ul>
{% endif %}
{% endblock main %}
Maybe this can be of any help.
#route(_(r'^detail/(?P<activity_slug>[-\w]+)/$'))
def show_activity(self, request, activity_slug):
activity_model_class = self.activity_model_class
if not activity_model_class:
raise Http404('No activity model.')
else:
queryset = self.get_activity(activity_slug)
try:
activity = queryset.get()
except activity_model_class.DoesNotExist:
raise Http404('activity not found')
else:
self.current_url = self.get_url(
'show_activity',
kwargs = {'activity_slug': activity_slug}
)
Now the routable page has a current_url
def get_context(self, request, *args, **kwargs):
context = super().get_context(request)
context['current_url']= self.current_url
return context
And now it’s in the context.

Django: How to write an if statement

I want to get the list of songs under the list of artists.
My artist class just contains the artists first and last name.
My song class contains a foreign key of an artist along with the song title.
I am able to list the artists but when I try to list the songs of the artist I get and error in my {% endif %} that ends my if statement {% if song %}.
{% extends "base.html" %}
{% block heading %}Music Catalog{% endblock %}
{% block content %}
{% if user.username %}
<p>Welcome {{ user.username }}!</p>
{% if artist %}
<u1>
{% for singer in artist %}
<li>{{ singer.firstname }} {{ singer.lastname }}</li>
{% if song %}
<u1>
{% for songs in song %}
{% if (songs.artist.firstname == singer.firstname
and songs.artist.lastname == singer.lastname) %}
<li>{{ songs.title }}</li>
{% endif %}
{% endfor %}
</u1>
{% endif %}
{% endfor %}
</u1>
{% else %}
<p>No artists were found in the music catalog.</p>
{% endif %}
{% else %}
<p>You need to login to see your music catalog.</p>
{% endif %}
{% endblock %}
enter code here
I don't think so, in the template language if statement you can use round bracket it won't parse. Try by removing it...
{% if songs.artist.firstname == singer.firstname and songs.artist.lastname==singer.lastname%}
It seems that your view should be handling more of this logic. Like Raunak Agarwal mentioned if you are passing your song or songs in to the template then each one is going to be the same.
It's very strange as well to be doing a
{% for songs in song %}
That just doesn't read right.
I would visit the view a little closer. I had written some more below. After looking over your code though taking a look at the view as well as the model would shed some light on things and allow for a much better help/answer to be given.
As you said My song class contains a foreign key of an artist along with the song title. - why don't you just use the regroup feature?
{% regroup song by artist as artist_list %}
<ul>
{% for artist in artist_list %}
<li>{{ artist.grouper }}
<ul>
{% for songs in artist.list %}
<li>{{ songs.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Yes, your if song line is incorrect. It's quite clear from the template that you don't even have a song attribute at that point. Where is it supposed to be coming from? Presumably it's a related set on singer, but you haven't said so in the template.
You probably want something like this:
{% for singer in artist %}
<li>{{ singer.firstname }} {{ singer.lastname }}
{% with songs as singer.song_set.all %}
{% if songs %}
<ul>
{% for song in songs %}
<li>{{ song.title }}</li>
{% endfor %}
</uL>
{% endif %}
{% endwith %}
</li>
{% endfor %}
I've also removed that comparison of artist firstname and lastname, that didn't seem to make sense: you're already iterating through the set of songs from that artist, so no comparison is needed.

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

Django template conditional variable assignment

I want to assign a variable do different values depending on if a variable exists, is this possible? My non working example might make it clearer:
{% if username %}
{% with menu_user=username %}
{% elif recent_users %}
{% with sorted_users=recent_users|dictsortreversed:"timestamp" %}
{% with menu_user=sorted_users.0.username %}
{% endif %}
{% if menu_user %}
<div id="menu">
<ul>
<li>Profile</li>
<li>Products</li>
</ul>
</div>
{% endif %}
{% if recent_users %}
{% endwith %}
{% endif %}
{% endwith %}
Pseudocode of what I try to do:
if username:
menu_user = username
elif recent_users:
menu_user = sorted(recent_users)[0]['username']
if menu_user:
<div id="menu">
<ul>
<li>Profile</li>
<li>Products</li>
</ul>
</div>
update
Then its better to customize a template tag like
#register.inclusion_tag('menu_snippet.html') # or you could use takes_context=True and fetch values from the context
def render_menu(username, recent_users):
if username:
menu_user = username
elif recent_users:
# sorted here could be replaced by min or QuerySet method, it depends
# for example:
# menu_user = min(recent_users, key=lambda u:u.timestamp).username
menu_user = sorted(recent_users)[0]['username']
return {'menu_user':menu_user}
# in template, it looks like
{% render_menu username recent_users %}
Putting the code in the view is much better. Just as your pseudocode, clean and readable.
If you still want to write template, I prefer something like
{% if username %}
<div id="menu">
<ul>
<li>Profile</li>
<li>Products</li>
</ul>
</div>
{% else %}
{% if recent_users %}
{% with sorted_users=recent_users|dictsortreversed:"timestamp" %}
{% with menu_user=sorted_users.0.username %}
<div id="menu">
<ul>
<li>Profile</li>
<li>Products</li>
</ul>
</div>
{% endwith %}{% endwith %}
{% endif %}
{% endif %}
Depends on your actual usage, customized template tag or the include tag are also possibly useful.
Template tag:
#register.assignment_tag
def alias(obj):
"""
Alias Tag
"""
return obj
Template:
{% alias sorted_users.0.username as menu_user %}
Create a template tag that takes username and recent_users as arguments which then outputs the menu. That way you will keep your template clean from that kind of logic.

Django regroup not working as expected

I have the following view in my django application
def ViewSale( request ):
salecur = Sale.objects.filter(user=2).order_by('sale_date')
return render_to_response('myapp/sale.html',{'salecur':salecur})
my template looks like this
{% regroup salecur by sale_date as sale_list %}
<ul>
{% for sale_date in sale_list %}
<li>{{ sale_date.grouper }}
<ul>
{% for sale in sale_list %}
<li>{{ sale.item }} - {{ sale.qty }} </li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
When i render the page i get the grouper sale_date.grouper printed, but {{ sale.item }} and {{ sale.qty }} in the inner loop shows nothing! Blank.
What am i missing?
Gath
{% regroup salecur by sale_date as sale_list %}
<ul>
{% for sale_date in sale_list %}
<li>{{ sale_date.grouper }}
<ul>
{% for sale in sale_date.list %}
<li>{{ sale.item }} - {{ sale.qty }} </li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
See the documentation on regroup:
{% regroup %} produces a list of group objects. Each group object has two attributes:
grouper -- the item that was grouped by (e.g., the string "Male" or "Female").
list -- a list of all items in this group (e.g., a list of all people with gender='Male').