Django - use template tag and 'with'? - django

I have a custom template tag:
def uploads_for_user(user):
uploads = Uploads.objects.filter(uploaded_by=user, problem_upload=False)
num_uploads = uploads.count()
return num_uploads
and I'd like to do something like this, so I can pluralize properly:
{% with uploads_for_user leader as upload_count %}
{{ upload_count }} upload{{ upload_count|pluralize }}
{% endwith %}
However, uploads_for_user leader doesn't work in this context, because the 'with' tag expects a single value - Django returns:
TemplateSyntaxError at /upload/
u'with' expected format is 'value as name'
Any idea how I can get round this?

You could turn it into a filter:
{% with user|uploads_for as upload_count %}

While a filter would still work, the current answer to this question would be to use assignment tags, introduced in Django 1.4.
So the solution would be very similar to your original attempt:
{% uploads_for_user leader as upload_count %}
{{ upload_count }} upload{{ upload_count|pluralize }}
Update: As per the docs assignment tags are deprecated since Django 1.9 (simple_tag can now store results in a template variable and should be used instead)

In Django 1.9 django.template.Library.assignment_tag() is depricated:
simple_tag can now store results in a template variable and should be used instead.
So, now simple tag we can use like a:
It’s possible to store the tag results in a template variable rather
than directly outputting it. This is done by using the as argument
followed by the variable name. Doing so enables you to output the
content yourself where you see fit:
{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p>

Related

Template tag as filter value in Django

I have defined one custom tag which is working fine in templates.
Like
{% get_setting "DATE_FORMAT_UI" %}
Above statement is returning correct value in template.
Now i want to use the same in a filter like this -
{{extra_info.to_date|date: '{% get_setting "DATE_FORMAT_UI" %}' }}
But this is giving error in parsing.
I tried in different ways of using quotes for the {% get_setting "DATE_FORMAT_UI" %}
But every time bad luck.
So could any body help me in solving this. I want to pass date format in filter . That date format is saved into config file. but how to pass that value dynamically in filter.
The trick is to first assign this to a variable (here myformat), and then use that variable:
{% get_setting 'DATE_FORMAT_UI' as myformat %}
{{extra_info.to_date|date:myformat }}

Django custom template filter feeding cookie or default value

I'm designing a custom django filter, just to make sure it works I have something like this
{{ "Sleeps:"|translate:"fr" }}
and it works.
Now in the final implementation, I want it to get a cookie or else use a default value
{{ pg.title|translate:request.COOKIES.lang|default:"en" }}
I'm getting this error
VariableDoesNotExist at /chalet/belle-chery
Failed lookup for key [lang] in {'_ga': 'GA1.1.1026479868.1547798010', 'cookie-policy': 'true', 'csrftoken': 'VrVrvgZUfFrWhFDFjLIvZgOus9NrmjDx1JwNP2lzvz2FRAGmC1lLrKwiH4g31X5F', 'sessionid': 'ptp6smvt9w95qtqlkc7klx736u5k7uu5'}
so it doesn't implement the default part.
So I figure there's either a way to fix this or use middleware to set the cookie if it's not set.
Would be nice if it doesn't need middleware.
so it doesn't implement the default part.
It does, it applies the |default:"en" filter to the result of {{ pg.title|translate:request.COOKIES.lang }}, not to the request.COOKIES.lang expression.
The easiest way to solve this is probably defining a local variable, for example with the {% with ... %} template tag:
{% with lang=request.COOKIES.lang|default:"en" %}
{{ pg.title|translate:lang }}
{% endwith %}

how to stop django template code from escaping

Is there any way to completely turn off django auto_escaping when rendering a template within the view code (for an email for example):
from django.template import Context, Template
subject_template_string = "Hi {{ customer.name }}"
subject_template = Template(subject)
context = Context({'customer':MyCustomerModel.objects.get(pk=1)})
subject = subject_template.render(context)
If customer.name is something like "Jack & Jill" - the subject looks like "Hi Jack &\amp; Jill" (without the backslash!)
is there something like
subject = subject_template.render(context, autoescape=False)
edit: The actual templates are created by the client in the database, I'm hoping to avoid having to say add |safe to all templates where this might happen...
Disabling it globally is usually a bad idea since you can easily forget it. I would recommend using the templatetag to disable it for that portion of your template instead.
Something like this:
{% autoescape off %}
This will not be auto-escaped: {{ data }}.
Nor this: {{ other_data }}
{% autoescape on %}
Auto-escaping applies again: {{ name }}
{% endautoescape %}
{% endautoescape %}
How about using mark_safe:
Explicitly mark a string as safe for (HTML) output purposes. The
returned object can be used everywhere a string or unicode object is
appropriate.
It marks a string as safe, so, you should take customer.name out and pass to the template:
from django.utils.safestring import mark_safe
customer = MyCustomerModel.objects.get(pk=1)
context = Context({'customer_name': mark_safe(customer.name)})
subject = subject_template.render(context)
Though, control what is safe or not is better to do inside the template itself, that's why using autoescape should be preffered.
Use Django's autoescape tag:
{% autoescape off %}
{{ body }}
{% endautoescape %}
for more info, check out the docs here.
This is untested, but based on source code review it looks like the context object can take autoescape as a key.
context = Context({'customer':MyCustomerModel.objects.get(pk=1), 'autoescape': False})
subject = subject_template.render(context)
That said, that's a pretty sweeping change. If you know what values the templates might be looking for, it's probably better to use mark_safe on those values and pass in the predefined options. That would have the added benefit of not risking the possibility of the client template calling a method with side effects on the customer. The first time someone writes a template and puts in {{ customer.delete }}, you have a problem.
Just came back to answer my own question with a simple solution, and there were already 4 answers.. thanks.
This is what I've gone with:
subject_template = Template(u'{%% autoescape off %%}%s{%% endautoescape %%}' % email.subject)

Is there any way to distinguish between two templatetags that have the same name?

I have 2 different template tags that share the same name: the_template_tag.
Is there any way to distinguish between the two template tags? Something like "source1.the_template_tag" and "source2.the_template_tag"?
Here is my case. I am using django-timezones. There is a templatetag called localtime that basically allows me to display the date in the client local time.
{% load timezone_filters %}
... some more code
"user_localtime": "{{ serverdate|localtime:user_timezone }}",
Also, I am using the new timezones of Django 1.4. When I need to use the client local time (with the django-timezone), then I start to have problems. Basically, I have to turn off the timezones of django:
{% load tz %}
... some more code
{% localtime off %}
But the templatetag is the same. Then, of course, I get an error when I try to use both:
{% load tz %}
{% load timezone_filters %}
... some more code
{% localtime off %}
"user_localtime": "{{ serverdate|localtime:user.user_timezone }}",
You have two options:
Stop using django-timezones and use the timezone features of django 1.4
If you must use django-timezones, edit the source and rename the tag.
I would highly recommend #1, and strongly discourage #2.

Django Custom Template Tag with Context Variable Argument

I have a custom template tag which shows a calendar. I want to populate certain items on the calendar based on a dynamic value.
Here's the tag:
#register.inclusion_tag("website/_calendar.html")
def calendar_table(post):
post=int(post)
imp=IMP.objects.filter(post__pk=post)
if imp:
...do stuff
In my template, it works fine when I pass a hard coded value, such as
{% load inclusion_tags %}
{% calendar_table "6" %}
However when I try something like {% calendar_table "{{post.id}}" %} , it raises a error a ValueError for the int() attempt. How can I get around this?
You want {% calendar_table post.id %}; the extra {{ and }} are what are causing you the heartburn.
Note that, in your custom tag, you need to take the string ("post.id") that gets passed and resolve it against the context using Variable.resolve. There's more information on that in the Django docs; in particular, look here: http://docs.djangoproject.com/en/1.3/howto/custom-template-tags/#passing-template-variables-to-the-tag