Does default_if_none have any use in Django templates? - django

From the Django docs,
Generally, if a variable doesn't
exist, the template system inserts the
value of the
TEMPLATE_STRING_IF_INVALID setting,
which is set to '' (the empty string)
by default.
Filters that are applied to an invalid
variable will only be applied if
TEMPLATE_STRING_IF_INVALID is set to
'' (the empty string). If
TEMPLATE_STRING_IF_INVALID is set to
any other value, variable filters will
be ignored.
This behavior is slightly different
for the if, for and regroup template
tags. If an invalid variable is
provided to one of these template
tags, the variable will be interpreted
as None. Filters are always applied to
invalid variables within these
template tags.
If an invalid variable always gets translated to '', for template tags and filters other than if, for and regroup, then what good does the template filter default_if_none do? Obsolete?

There is a difference between an invalid variable and one that exists but has a value of None.
Consider the following context:
{'apple':'green','banana':None}`
In your template {{ apple }} resolves to green, while {{ banana }} resolves to None, and {{ orange }} resolves to TEMPLATE_STRING_IF_INVALID.
Now consider {{ banana|default_if_none:'yellow' }} and you should see the use of the default_if_none tag.

Here's a case where I have used default_if_none a few times. I'm querying a secondary database in which I have no control and I'm displaying the data in the template. Most of the times the data looks fine but sometimes, the data value will show None. In that case, I will use the filter as:
{{ data_value|default_if_none:"N/A" }}
The general public and users of site doesn't usually understand what the None value means, by replacing it with a more friendly word, the filter default_if_none comes in handy.

I have a Django model with a method returning the the number of days a trade has been open (an integer). For the first 24 hours it returns 0. However, once the trade is closed, it returns None.
In this situation, the distinction between default and default_if_none is important... I need to use default_if_none... otherwise, for the first 24 hours a trade is open, it looks as if they were already closed (because zero is falsy).

Related

Is it better to have an explicit django model field or calculate on demand?

If I have a django model that has an field called 'order' (integer field that tracks the modifiable order of a specific model instance amongst all model instances), and I also want to track the position of the model instance based on that order ('first'/'mid'/'last'), is it better to have another model field called 'position', which I recalculate and store each time there is a change to order, or should I have a model method called 'get_position' which I call each time I need a position. I'm trying to work out which is more efficient. Whilst I won't need the position information each time I create/delete/modify a instance order, I will need that position field quite a bit within my templates.
Generally avoid creating an additional database fields if something can be calculated from data already in the db, to prevent redundancy and reduce vectors for errors.
A method may work if its relatively simple, deriving its value from an existing field within the record. If it needs to look up comparative values from other records that would be an efficiency issue.
As you mention use in templates specifically, it may be worth seeing if the template builtins can meet your requirements.
Say your recordset is already in order of the 'order' field eg,
MyRecords.objects.order_by('order')
When looping through MyRecords_context in a template using a for loop, you can test for {{if forloop.first}} or {{if forloop.last }} - you can also refer to MyRecords_context.first() and .last() to single those out. If you need the specific index of a given record in that particular recordset for you template, you can refer to {{ forloop.counter }} eg {{if forloop.counter < 10 and forloop.counter > 5}} or {{if forloop.counter == 5}}
The advantage of this approach is that if you have a filtered a subset of your records, you are still referring to the first, last or Nth records of the recordset, even though they may not be first and last overall in your absolute position field, and with no additional db calls.

Django: display a preview of an object's attribute - Class based views

Using a ListView Class-based-view, I am looping over the objects present in the database of a certain model in my HTML template, and, for instance, I can access an object's "body_text" attribute with the following syntax: {{object.body_text}}
What if I wanted to only show the first 20 characters of that "body_text" attribute in my HTML template?
How can I set that?
1st Method
Use the truncatechars filter in your HTML template.Truncates a string if it is longer than the specified number of characters. Truncated strings will end with a translatable ellipsis character (“…”).
{{object.body_text|truncatechars:20}}
Reference:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#truncatechars
2nd Method
Use the slice filter in your HTML template.
{{object.body_text|slice:":20"}}
Referernce: https://docs.djangoproject.com/en/dev/ref/templates/builtins/#slice
Found it, eventually.
Use the |slice:":" filter in your HTML template.
For example, if you only want to display the first 10 characters of a given attribute, use:
{{object.body_text|slice:":10"}}

Write not fully displayed Django field

I need to write a Django custom field where the stored value is not fully displayed.
For example if the stored value is "079684" I need it to be displayed as "---84". Is it possible to do so ? If yes how should I implement my custom field ?
I have solved this by overriding from_db_value() of the custom field method.
You could store your value as a string in your model and than use slice in template to show only last two character.
{{ value|slice:"-2:" }}

Flask-SQLAlchemy number of results in query

I was wondering if anyone knows how to output the number of results from a query in a flask template.
Example view code:
products = Product.query.all()
In the template it would be handy to be able to just do:
{{ products.count() }}
Is there anyway to do this already, or does anyone have a filter written that does this?
Cheers,
Your products template variable is a regular list. You can use the length filter to gets its size:
{{ products|length }}
But if you are working with paginated results then this will give you the size of one page. If you want the size of the entire query then you have to call count() on the query object. For example:
product_count = Product.query.count()
Then pass this to the template as an additional argument. Or if you prefer you can pass the query object to the template and call count() from there:
{{ product_query.count() }}
you can use len(products) ,
it is standart python function and works for me

Is it possible to replace values in a queryset before sending it to your template?

Wondering if it's possible to change a value returned from a queryset before sending it off to the template.
Say for example you have a bunch of records
Date | Time | Description
10/05/2010 | 13:30 | Testing...
etc...
However, based on the day of the week the time may change. However this is static. For example on a monday the time is ALWAYS 15:00.
Now you could add another table to configure special cases but to me it seems overkill, as this is a rule. How would you replace that value before sending it to the template?
I thought about using the new if tags (if day=1), but this is more of business logic rather then presentation.
Tested this in a custom template tag
def render(self, context):
result = self.model._default_manager.filter(from_date__lte=self.now).filter(to_date__gte=self.now)
if self.day == 4:
result = result.exclude(type__exact=2).order_by('time')
else:
result = result.order_by('type')
result[0].time = '23:23:23'
context[self.varname] = result
return ''
However it still displays the results from the DB, is this some how related to 'lazy' evaluation of templates?
Thanks!
Update Responding to comments below:
It's not stored wrong in the DB, its stored Correctly However there is a small side case where the value needs to change.
So for example I have a From Date & To date, my query checks if todays date is between those. Now with this they could setup a from date - to date for an entire year, and the special cases (like mondays as an example) is taken care off. However if you want to store in the DB you would have to capture several more records to cater for the side case. I.e you would be capturing the same information just to cater for that 1 day when the time changes. (And the time always changes on the same day, and is always the same)
Update with Solution (Based on answer by KillianDS below)
In models.py i defined a custom property:
#property
def get_corrected_time(self):
from datetime import time
day = datetime.now().weekday()
if day == 0 or day == 1:
self.time = time(12,30)
return self.time
and in the template
{{ object.get_corrected_time|time:"P" }}
The reason for returning a datetime.time object rather then a string is, django's default date & time filters will not work on a string.
Okay, without any precise example (a simple model & clear use case would help), I can't really be sure, but I guess this is what you want to do. In your model definition, add something like this:
#property
def get_corrected_time(self):
if today_is_monday:
return '13:30'
return str(self.time)
in your template you can perfectly call this as {{ object.get_corrected_time }}
Now I see in your template tag you want to do this for example only on the first element in a queryset, you can easily do this as follows in the template (you could also do it in the view method):
{% for object in list %}
{% if forloop.first %}
{{ object.get_corrected_time }}
{% else %}
{{ object.time }}
{% endif %}
{% endfor %}