Generating a date relative to another date in Django template - python

I have a date in my template context, and I want to display that date plus 7 days in the rendered output.
Something like this (which does not exist):
{{some_date|plus_days:7}}
How can I do this in a Django template without writing any Python code?

You can create your own template tag:
import datetime
from django import template
register = template.Library()
#register.filter
def plus_days(value, days):
return value + datetime.timedelta(days=days)

This cannot be done in Django templates as of this writing without writing a custom template tag in Python.

Related

Django: dynamically mapping views in urls.py

I have a viewsdirectory containing say a hundred view files. How can i make my urls.py transfer control to these view files without putting in an "intermediate handler" as described here (answered 3 years back).
Basically- is there a cleaner way for redirecting control to views in django?
The view function returns an HTML page that includes the current date and time. To display this view at a particular URL, you’ll need to create a URLconf; see URL dispatcher for instructions.
https://docs.djangoproject.com/en/1.7/topics/http/urls/
For redirecting you should use the Django redirect shortcut function
from django.shortcuts import redirect
def my_view(request):
...
return redirect('some-view-name', foo='bar')
https://docs.djangoproject.com/en/1.7/topics/http/shortcuts/#redirect

Django splitting a textfield using template tags

I know that I can use {{value|truncatewords:x}} to truncate a textfield after a given number of words. Is it possible to use the truncated part afterwords if I want to sandwich something in between the text? Like using a string in python if I were to give
>>>string[:2]
>>>something in between
>>>string[2:]
but using template tags because I am iterating through a for loop and cannot pass it through my views?
Thanks
You would need a custom template filter here.
Here's a simple example based on truncatewords() filter implementation:
from django import template
from django.template.defaultfilters import stringfilter
from django.utils.text import Truncator
register = template.Library()
#register.filter(is_safe=True)
#stringfilter
def sandwich(value, args):
length, cutlet = args.split(',')
length = int(length)
truncated_value = Truncator(value).words(length, truncate='')
return ' '.join([truncated_value, cutlet, value[len(truncated_value):].strip()])
Example output:
>>> from django.template import Template, Context
>>> template = Template('{% load filters %}{{ value|sandwich:"2,magic" }}')
>>> context = Context({'value': 'What a wonderful world!'})
>>> template.render(context)
u'What a magic wonderful world!'
Note that Django doesn't allow multiple arguments to be passed in the template filter - that's why they are passed as a comma-separated string and then parsed. See more about the idea here: How do I add multiple arguments to my custom template filter in a django template?
Also, you would probably need to catch possible exceptions in case only one argument passed in the string, the length value cannot be converted to int etc.

print page generation time

how would I print the time it took to render a page to the bottom of my site in django? i'm not sure of the application flow of django, so I don't know how this would work.
You might be interested in django-debug-toolbar, which includes a request timer and lots of other useful info for debugging things like this.
At the beginning of your view handler, save the current date/time in a variable say time_start and pass that to the template context which renders the page.
Then define a custom template filter that will create timedelta based on datetime.now() value and the original datetime passed in as a parameter like so:
from datetime import datetime
from django import template
register = template.Library()
#register.filter
def get_elapsed(time_start):
return str(datetime.now() - time_start)
Then in your template, simply display:
...
{{ time_start|get_elapsed }}
...

Get template name in template tag ( Django )

is there a way to get the template name ( being parsed ) in a template tag ?
I have read searched and found nothing, only this previous post
Getting the template name in django template
which doesn't help me much, since the answer relies on settings.DEBUG being true, which in my case can't be.
I don't really know where to start on this one, so any suggestion is welcome :)
EDIT
So basically what i want is to create a plugable tag that when rendered it checks for a Tag object, this would be the source for the tag object
class Tag(models.Model):
template = models.CharFIeld(max_length=50)
name = models.CharField(max_length=100)
plugins = models.ForeignKey(PluginBase)
if theres a tag object, then it displays all plugin objects, if not it creates a tag object unique to the name provided in the template tag and the template name, if getting the template name is not possible, then i guess i can just make it unique per name. The whole tag is kinda like a placeholder, for those familiar with django-cms
You could perhaps do this with a context processor, but I'm not sure if these have access to the name of the template.
What will work is to make a wrapper for the rendering calls you do. Say you currently do the following:
from django.shortcuts import render
def index(request):
return render(request, 'app/index.html', { 'foo': 'bar', })
If you create your own wrapper for this, you could add the template name to the dictionary before the actual render takes place:
from django.shortcuts import render
def myrender(request, template, dictionary):
dictionary.update({'template_name': template})
return render(request, template, dictionary)
Then in your views, change it as follows (assuming you saved the above function in myutils.py, and it is available on your path):
#from django.shortcuts import render <- delete this line
from myutils import myrender as render
def index(request):
return render(request, 'app/index.html', { 'foo': 'bar', })
Now all your render calls will update the dictionary with the template name. In any template, then just use {{ template_name }} to get the name. You can of course also update other rendering function like render_to_response and such in a similar fashion.
Also, the import myrender as render might or might not confuse you later on because it is named like the Django function... if so, just import it without the "as render", and replace all render calls with myrender. Personally I'd prefer this since this makes it a drop-in replacement for the existing rendering functions.
Looking at the source, while the Template object would have access to the template name (via .name) this value is never passed on to the Parser object and therefore not available to template tags.
There are various ways of making the template name available to the template itself (by adding it to the context) but not within the template tags.
As Daniel Roseman mentioned in the comments, if you can elaborate on what you're actually trying to achieve, there may be a better way to achieve what you want. No offence, but this sounds like it may be an XY problem.
Out of academic interest, I had a quick fiddle to see if it was possible. As far as I can see, it is possible but not without changing or monkey patching the django source.
Note: the following is not a recommended solution and merely hints at what may be required to actually make this work. Not to be used for production code.
By modifying django.template.base.py with the following changes, we add the .template_name attribute to the parser object making it available to template tags.
Added optional arg to compile_string
Added template name as extra attribute to parser
Passed in the template name when calling compile_string()
To test this out, I defined the following tag which simply returns the template name in caps:
from django.template.base import Node, Library
register = Library()
class TemplateNameNode(Node):
def __init__(self, template_name):
self.name = template_name
def render(self, context):
return self.name.upper()
#register.tag
def caps_template_name(parser, token):
return TemplateNameNode(parser.template_name)
and the following template:
{% load mytags %}
Template name in caps: {% caps_template_name %}
This seems to work when tested in ./manage.py shell:
>>> from django.template import loader, Context
>>> t = loader.get_template("test.html")
>>> t.render(Context({}))
u'\nTemplate name in caps: TEST.HTML\n'
While this seems to work, I should reiterate that manually patching the django source never a good solution and is subject to all sorts of misery when migrating to different versions.

Calculate number of days between two dates inside Django templates

I have two dates and want to show a message like "n days left before your trial end." where n is a number of days between two given dates. Is that better to do this inside views or is there a quick way to do it inside template itself?
Use timesince template tag.
This code for HTML in Django. You can easily find the remaining days.
{{ to_date|timeuntil:from_date }}
Otherwise, you can use custom TemplateTags.
Possible duplicate here
I'd actually use the same method lazerscience uses, something like this:
from datetime import datetime, timedelta
from django import template
from django.utils.timesince import timesince
register = template.Library()
#register.filter
def time_until(value):
now = datetime.now()
try:
difference = value - now
except:
return value
if difference <= timedelta(minutes=1):
return 'just now'
return '%(time)s ago' % {'time': timesince(value).split(', ')[0]}
In the HTML template, you can do the following:
{{ comments.created|timeuntil:project.created }}
And you get output something like this:
1 hour, 5 minutes

Categories