Why is widthratio (multiplication) not working in my template? - django

I'm using Django 2.0 and Python 3.7. I've read I can do multiplication in templates by using widthratio -- multiplication in django template without using manually created template tag . However, in a template of mine, I'm trying this to no avail. I'm trying
{% if widthratio articlestat.score 1 TRENDING_PCT_FLOOR >= articlestat.weighted_score %}style="font-weight:bold;"{% endif %}
When my template is executed with this code, it gives the error ...
Unused 'articlestat.score' at end of if expression.
I want my if expression to say if the multiple of "articlestat.score" and "TRENDING_PCT_FLOOR" is greater than "articlestat.weighted_score," print this out, but I can't seem to figure out how to do that.

You can't use template tags inside if statement conditionals like that. What you can do is first assign the output of widthratio to a template variable, and then compare that in your if statement:
{% widthratio articlestat.score 1 TRENDING_PCT_FLOOR as ratio %}
{% if ratio >= articlestat.weighted_score %}style="font-weight:bold;"{% endif %}

I have the habit of using template tags only for pure templating questions (e.g. formating a number to dollars) and leaving all logic to the models (if the logic is model-specific) or views (if it's a business logic or depends on what view you're in).
Instead of using a custom template tag, would add a property to the articlestat model when TRENDING_PCT_FLOOR is static:
class ArticleStat(models.Model):
TRENDING_PCT_FLOOR = x
#property
def is_ratio_positive(self):
ratio = self.score * self.TRENDING_PCT_FLOOR
return ratio >= self.weighted_score
Then on the template, I would use:
{% if articlestat.is_ratio_positive %}style="font-weight:bold;"{% endif %}
If articlestat is not a model (e.g. it was created on views.py) then I would use the logic above on the corresponding view.

Related

How to use "for" statement in Django template

Here is Django template code.
I tried to put out images to template.
amount of image put out to template is depending on {{object.image_amount}}
However since {{object.image_amount}} is an integer I can not iterate like this
{% for i in object.image_amount %}
So I tried this but does not work as well.
{% for i in range object.image_amount %}
What should I do?
if you already have images that you need to show in your template
something like object.images or object.images.all if its related model
you can do
{% for image in object.images.all %}

How to make context variable dynamic in django template

Is it possible to append 2 context variables together into a single context variable that is calculated at run-time?
For example: if I have {{contextA}} (which equals 1) and {{contextB}} (which equals 'building') and I wanted to add these together to get context {{1building}} How would I do this?
I have tried:
{{contextA + contextB}}
{{{{contextA}} + {{contextB}}}}
{{contextA |add: contextB}}
{{contextA contextB}}
I suppose this is not possible and this needs to be done in the view using python, but it would be ideal if I could just combine context variables in the template.
U can use {% with template tag as follows (docs here -> https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#with)
{% with newvar=contextA|add:contextB %}
{{ newvar }}
{% endwith %}
newvar will have a new value if into a forloop where contextA or contextB change it's value.
As you want to show the value of a context variable with it's name equal to newvar value, the way to accomplish it is to create a custom template tag as follows:
#register.simple_tag(takes_context=True)
def dynvarvalue(context, dynvarname):
""" Returns the value of dynvarname into the context """
return context.get(dynvarname, None)
I did a small proof of concept:
{% with 1building='1 building value' contextA='1' contextB='building' %}
{% dynvarvalue contextA|add:contextB %}
{% endwith %}
Which produces the following output, which I think is what you are asking for:
1 building value
Hope this helps.
Note: take into account that if both variables can be transformed to an integer, they will not be concatenated and will be summed as docs says (https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#add)
Note2: I think there are some security caveats to take into account doing this.

Invalid Filter Template Error Django 1.11

This is my filter:
from django import template
register = template.Library()
#register.simple_tag(name='addition')
def addition(*args):
return round(sum(list(args)), 1)
This is the error:
Invalid filter: 'addition'
In my template:
{% load static %}
{% load math_filters %}
This is the filter in the template:
`{{ ASEL.total_time|addition:"AMEL.total_time, ASES.total_time, AMES.total_time" }}`
I want the filter addition to accept any number of arguments and add the numbers together
I've followed the docs to the T and still can't get the tag to register.
templatetags dir is at the same level as models.py and contains __init__.py
I'm totally lost. Any ideas?
Limitations of template filters
I want the filter addition to accept any number of arguments and add the numbers together.
A custom template filter can not take more than one parameter on the right (and the implicit parameter on the left), as is specified in the documentation:
Custom filters are just Python functions that take one or two
arguments:
The value of the variable (input) – not necessarily a string.
The value of the argument – this can have a default value, or be left out altogether.
Personally I do not really understand why you want to do that anyway. You could make the granularity of the tag finer, and write it like:
{{ ASEL.total_time|add:AMEL.total_time|add:ASES.total_time|add:AMES.total_time|some_round }}
(where you can implement some_round template filter to round the result).
You can also solve this by taking one optional parameter, for example a string, and then perform string processing, but this will usually only result in more complicated code, probably bugs included.
Using template tags
You can however define a template tag, template tags can take multiple parameters (both positional and named ones). For example:
# app/templatetags/math_filters.py
#register.simple_tag
def addition(*args):
return round(sum(list(args)), 1)
Then you can write it like:
{% load math_filters %}
{% addition ASEL.total_time AMEL.total_time AMES.total_time %}
or if you want to store the result in a variable:
{% load math_filters %}
{% addition ASEL.total_time AMEL.total_time AMES.total_time as some_variable %}
Note: since variable can contain all kinds of type, you might want to make the template tag more flexible to interpret strings, etc. as numerical values.

Using the Django assignment_tag built-in tag the right way

I'm working on a project in Django.
Earlier today, I discovered the new (Django >= 1.4) assignment_tag. I immediately decided that it was just what I needed EVERYWHERE and threw some logic into one that executed a very simple query against the database and returned the resulting queryset. The function I wrapped takes an argument that allows the invoking context to specify how many results to grab, directly in the template when I am using the template tag.
It is quite convenient - I don't have to update my view when I decide this list should have 5 items, not 3 - but it seems like one of those gray areas where we aren't supposed to tread (i.e. pushing application logic into templates) when writing good, maintainable Django code.
Now, a couple of hours separated from writing the code, I'm wondering if I should scrap the assignment_tag entirely.
Code:
models.py:
class SomeObject(models.Model):
is_active = models.BooleanField(default=False)
(...)
templatetags/myapp_tags.py:
from django import template
from myapp.models import SomeObject
register = template.Library()
#register.assignment_tag
def get_someobjects_list(max_results=0):
queryset = SomeObject.objects.filter(is_active=True)
if max_results == 0:
return queryset
elif max_results > 0:
return queryset[:min(max_results, queryset.count())]
else:
return None
templates/myapp/chunks/someobject_list.html:
{% load myapp_tags %}
{% get_someobjects_list as someobjects_list %}
# or {% get_some_objects_list 5 as someobjects_list %} ... flexible!
{% if someobjects_list %}
<ul>
{% for someobject in someobjects_list %}
<li>
<a href="{{ someobject.get_absolute_url }}">
{{ someobject.name }}
</a>
</li>
{% endfor %}
</ul>
{% else %}
<span>No someobjects exist</span>
{% endif %}
I was really excited to discover these existed - it's convenient for me in this particular case. Now that my excitement over finding a new feature has passed, it seems pretty clear that I'm misusing it. The example given in the Django docs seems like a better application of this - grabbing the string representation of current datetime, something that doesn't require a DB query. My worry is that I'm setting myself up for heartache if I start using this pattern regularly. Following the slippery slope all the way down: I'll end up not even bothering to pass a context to my templates and ALL my DB queries will be hidden away in template tags where nobody would think to look for them.
It seems the code would be cleaner if I just threw out this whole "great idea" I had when I discovered assignment_tags and created a custom model manager instead.
Are there other clean ways of accomplishing this that I am missing? Are manager methods the consensus best way among Django developers?
assignment template tags are especially helpful if you need to get some information into the template context for a few pages of a website, but don't want to (or can't) put the info into every view on the website, and don't want to or can't rely on a context processor.
they basically guarantee that your information will be available in the template.

Evaluate string as template tag - Django

I have a Django template which includes a template tag that takes a variable (shop.id) and returns one of two string depending on whether the shop is in a database model, like this
{% is_shop_claimed shop.id %}
The two possible strings returned by the template tag are
return '<p>Taken</p>'
or
return 'Claim shop now'
When the code is run, if the second string is returned, it appears in the template (viewing the page source in the browser) like
Claim shop now
and appears in the browser as a link like this
Claim shop now
The problem is that shop.id in the href is not evaluated to a number by the Django template engine.
The link should appear like this for shop 123, for example
Claim shop now
I've checked the Django docs for filters to apply to the string in the template tag or in the template so that the string is not escaped but no luck.
I have looked at this but it seems there should be a simple way making the {{shop.id}} evaluated in the template.
I have also made the template tag to return a Bool instead of the two strings, leaving the presentation in the template like I would prefer, but using an if statement around a template tag like this
{% if is_shop_claimed shop.id %}
<p>Taken</p>
{% elif not is_shop_claimed shop.id %}
Claim shop now
{% endif %}
doesn't work because I can't put the template tag inside the if statement.
Any suggestions on how to get {{shop.id}} to be evaluated to a number? Any help would be appreciated.
I'm learning Django and Python and I have spend hours on this problem.
You're being passed the value, so just substitute it in.
return 'Claim shop now' % (shop_id,) # or however you refer to it in the code
I suggest you add an is_claimed property to you shop model:
class Shop(models.model):
# you fields are here
#property
def is_claimed(self):
# logik for determining if the shop is claimed
if claimed:
return True
else:
return False
Then you can use is in you template:
{% if shop.is_claimed %}
<p>Taken</p>
{% else %}
Claim shop now
{% endif %}
You could even move this to a snippet which you can include as need or (to go even further) create an inclusion tag for it.