Test date value in django views - django

In order to make sure my database values don't create null value exceptions I created a dummy date of 01-01-0001 in Postgresql.
However I want my views to return none if it's the dummy date in the view.
I tried the following but it's not working:
{% if myDate == "0001-01-01" %}
None
{% else %}
{{ myDate }}
{% endif %}

You can use Django date filter template tag
{% if myDate|date:"Y-m-d" == "0001-01-01" %}
None
{% else %}
{{ myDate }}
{% endif %}

Related

How to reference a foreign key in html django

{% for cred in allcreds %}
{% if cred.datasource.name == '...' %}
<h4>{{ cred.datasource }}</h4>
{% endif %}
{% endfor %}
In this case I check the datasource name in the conditional. Then it prints out the datasource. I want to have the datasource in the conditional.
I assume if you print out {{ cred.protocoldatasource }} it will output nothing, because your "relation" protocoldatasource does not exist.
The available foreign-keys that your model ProtocolUserCredentials has are: protocol, data_source, user, protocol_user.
So if you do
{% if cred.data_source.name == 'Demonstration Protocol, ...' %}
or any other of the mentioned relations you can access your related models.
Also note that {% if foo = 'bar' %} is invalid, you'll need to have == in the if-statement.

Django : filter Datefield in template

I'm using Django 1.5.8
I'd like to filter Datefield type data in template like following code.
express with timesince format for recent articles
express with date format for old articles
some_template.html
{% for article in articles %}
{# recent articles #}
{% if article.created >= (now - 7 days) %}
{{ article.created|timesince }}
{# old articles more than one week past #}
{% else %}
{{ article.created|date:"m d" }}
{% endif %}
{% endfor %}
Is there a solution to handle {% if article.created >= (now - 7 days) %} by django's own template tags?
Or do I have to make new custom filter?
Although I'm sure it's possible to do this with a custom template tag, I think you'll find it is a lot easier to implement this test in your model code. For example:
from datetime import date, timedelta
class Article(models.Model):
[...]
def is_recent(self):
return self.created >= date.today() - timedelta(days=7)
Then your template can be:
{% for article in articles %}
{% if article.is_recent %}
{{ article.created|timesince }}
{% else %}
{{ article.created|date:"m d" }}
{% endif %}
{% endfor %}

Detect row difference (view or model)?

I would like to display a list of publications on my website; however, I would also like to diaplay a header stating the year for each set of publications published on that particular year.
So I would like for my end result to be like this (my reputation is 1 :( I could not upload the image):
https://dl.dropboxusercontent.com/u/10752936/Screen%20Shot%202013-06-21%20at%206.00.15%20PM.png
I have a table with three columns; id (primary key), title (the title of the article), and date (the date of publications)
In my template file; doing the following will print the header before every article:
{% for curr_pub in all_publications %}
<h1>{{ curr_pub.date.year }}</h1>
<li>{{ curr_pub.title }}</li>
{% endfor %}
I am passing all_publications ordered by '-date' which means that I can compare the year of the current row curr_pub with the previous one and check if it differs or not; and print (or not print) the header accordingly. It seems however, that I cannot do that in the template.
Since I am new to Django and Python, I wasn't sure what to do and this is where I need help; my thoughts were the following:
1) Add a function in the model (def is_it_first_publication(self):) that returns true or false - but I really wasn't able to do that :| - ...and I'm not sure if that is what I needed to do or not!
2) Second one is to do in in the view, and pass extra variable(s) to the template; here's an example (which works just fine for this case):
In the view:
def publications(request):
all_publications = Publications.objects.order_by('-date')
after_first_row_flag = False
f_year = 'Null'
list_of_ids_of_first_publications = []
for curr_pub in all_publications:
if after_first_row_flag:
if curr_pub.date.year != f_year:
list_of_ids_of_first_publications.append(curr_pub.id)
f_year = curr_pub.date.year
else:
# The year of first (or earliest) publication has to be added
#
list_of_ids_of_first_publications.append(curr_pub.id)
f_year = curr_pub.date.year
after_first_row_flag = True
template = loader.get_template('counters/publications.html')
context = RequestContext(request, {
'all_publications': all_publications,
'list_of_first_publications': list_of_ids_of_first_publications,
})
return HttpResponse(template.render(context))
In the template:
{% for curr_pub in all_publications %}
{% if curr_pub.id in list_of_first_publications %}
<h1> {{ curr_pub.date.year }} </h1>
{% endif %}
<li> Placeholder for [curr_pub.title] </li>
{% endfor %}
The regroup built in filter can do this for you without annotating your objects in the view. As the documentation says, it's kind of complicated.
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#regroup
{% regroup all_publications by date.year as year_list %}
{% for year in year_list %}
<h1>{{ year.grouper }}</h1>
{% for publication in year.list %}
<li>{{ publication.title }}</li>
{% endfor %}
{% endfor %}
I think you want the regroup template tag;
{% regroup all_publications by date as publication_groups %}
<ul>
{% for publication_group in publication_groups %}
<li>{{ publication_group.grouper }}
<ul>
{% for publication in publication_group.list %}
<li>{{ publication.title }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Maybe the template tag regroup could help.
Alternatively, you could do this grouping by year in the view function (will try to provide code later).

reduce django db calls

I noticed that my django code calls my database very often with the exact same queries.
I understand that a db hit is made when I actually need the data to display on a page or to evaluate. However, my template code looks like this:
template:
{% if item.listing %}
{{ item.name }} text <strong>{{ item.listing|lowestprice }}</strong> more text
{% else %}
{{ item.name }} even more text
{% endif %}
....
{% for listed_item in item.listing %}
....
{% endfor %}
custom filter:
def lowestprice(value):
try:
val = unicode(value[0].price) + unicode(value[0].symbol)
return val
except:
return "not available"
This code hits my db three times. First on template {% if .. %} second on my custom filter, third on the {% for %} loop.
listing is a method of my models class which is returning a raw SQL queryset with some very expensive joins.
def listing(self):
return Universe.objects.raw("ONE HELL OF A QUERY")
How can I reduce my code to hit the db only once?
Edit: Using with works, but is it possible to avoid db hits on custom filters?
You should use with to do the expensive query once and store it the context.
{% with item.listing as item_listing %}
{% if item_listing %} ... {% endif %} ... etc ...
{% endwith %}

Django TemplateSyntax: Two tests with an 'If .. or...'

I am trying to run two tests:
{% if profile.id != 100 or profile.location == NULL %}
however it seems to not work. I couldn't find in the docs why this isn't working. Any ideas?
EDIT:
In the SQL db, the value for profile.location is NULL. The rendered result is None.
EDIT 2:
Here is the full chain. There are 4 ways to grab a user's location. It is a giant mess as you can see...
{% if profile.city.id != 104 or profile.city %}
{{profile.city}}
{% else %}
{% if profile.mylocation != '' %}
{{ profile.mylocation }}
{% else %}
{% if profile.fbconnect == 1 and profile.location != '' and profile.location != "None" %}
{{profile.location}}
{% else %}
{% if profile.sglocation.city %}{{profile.sglocation.city}}{% else %}{{profile.sglocation.country}}{% endif %}
{% endif %}
{% endif %}
{% endif %}
There's no NULL. Try:
{% if profile.id != 100 or not profile.location %}
If I were you, I would throw all that logic back into Python, for example:
class Profile(models.Model):
[your model fields and stuff]
def get_location(self):
[your location logic]
Then in the template you can just do:
{{ profile.get_location }}