Django Templates - Iterate over range - python

Intention
In my Django template, I create a link for each letter in the alphabet and each digit 1-9 to link to an index page.
In Python code, this is what it would look like:
for ch in map(chr, range(97, 123)) + range(1,10):
print '{0}'.format(ch)
But I want to do this in a Django template, so I can't use the map/range functions directly.
Failed Attempts
At first, I thought about creating a template tag that returns the alphanumeric character list, and then looping over it in the template, but this does not work, as it's a tag and not a context variable.
Templatetag:
#register.simple_tag
def alnumrange():
return map(chr, range(97, 123)) + range(1,10)
Template:
{% for ch in alnumrange %}
{{ch}}
{% endfor %}
I thought it might work when using the with tag, but it didn't either.
Further thoughts
I can't set the context in a view as this is a base template which I extend.
I don't want to add a context processor, as I use this range only in a single template.
Is there a way to turn the template tag output into a context variable over which I can iterate? Or is there another way I should solve this?

Check out this template tag: Template range tag. You should be able to extend it to handle characters as well.

You need inclusion tag here. Just pass your range in context and render it as you like. It gives you flexible and modular structure.

Related

How to include context variable in a wagtail cms field?

I am looking for a way to render a variable that will be available in the context of the the page where the cms page will be rendered.
Ex:
I have in the context the logged in user and I also have the last transaction he made on the website.
I would like the text in the rich text field in Wagtail to be like this so that the marketing team can tweak the copy.
Hello ||firstname|| thanks for your purchase. ||productname|| will be
shipped to you soon. The expected delivery date is
||expected_delivery_date||
To be less confusing I replace the double brackets by double pipes to show that the templating system does not need to be django templates for those ones. Simple templating is enough maybe using https://docs.python.org/3.4/library/string.html#template-strings
I think I can achieve this by doing:
A stream field that would have blocks of rich text field and a custom block with the possible context variable they can use
A custom render function that would regex and replace the merge tags in the rich text block with the context values
Create a new filter for simple templating. ex: {{ page.body|richtext|simpletemplate }}
Is there any more obvious way or out of the box way to do templating from within a rich text field?
It would be clunky with a separate streamfield block for each inserted context variable. You'd have to override the default rendering which wraps elements in div tags. However I like that it is more foolproof for the editors.
I've done something like the custom rendering before, but with simple TextFields for formatting special offer code messages. Wagtail editors were given the following help_text to illustrate:
valid_placeholders = ['offer_code', 'month_price']
template_text = models.TextField(
_('text'),
help_text="Valid placeholder values are: {all_valid}. Write as {{{example}}}".format(
all_valid=", ".join(valid_placeholders),
example=valid_placeholders[0],
)
)
This rendered as Valid placeholder values are: offer_code, month_price. Write as {{offer_code}}.
Then in the view:
template_keys = [i[1] for i in Formatter().parse(template_text)]
…and continued rendering from there. Remember to validate the field appropriately using the above Formatter().parse() function too.
I used Django's template formatting rather than Python's string.format() because it fails silently, but you could go with string.format() if cleaned adequately.
The custom template filter would feel easiest to me, so I'd start with that approach and switch to a custom render function if I ran into hurdles.
I found an easier way to do this. I wanted my editors to be able to create pages with dynamic customization to the individual user. With this, my editors are actually able to put template variables into any type of content block as {{ var }} which works just like the Django templating language. For my use case, I am allowing my editors to create email content in the CMS, then pulling that to send the emails:
This is the function to call:
def re_render_html_template(email_body, context):
"""
This function takes already rendered HTML anbd re-renders it as a template
this is necessary because variables added via the CMS are not caught by the
first rendering because the first rendering is rendering the containing block,
so instead they are rendered as plaintext in content the first render, e.g., {{ var }}
Example:
input: <p>Hey {{ user_account.first_name }}, welcome!</p>
output: <p>Hey Brett, welcome!</p>
#param email_body: html string
#type email_body: str
#param context: context dictionary
#type context: dict
#return: html string
#rtype: str
"""
from django.template import Context
from django.template import Template
template = Template(email_body)
context = Context(context)
email_body = template.render(context)
return email_body
Then I call it like so:
email_body = render_to_string(template, context)
# need to re-render to substitute tags added via CMS
email_body = re_render_html_template(email_body, context)

Django breadcrumb using generic tools

I would like to use Django build-in tools to print breadcrumb string in the html-template file, for example like this:
domain_name/accounts/14
Where each part between / will lead to its corresponding page. Is it achievable using {{ request.path }} and https://docs.djangoproject.com/en/1.9/ref/templates/builtins/ ?
The tasks I see:
Remove first slash '/' from the `{{ request.path }}'
Break {{ request.path}} value into pieces (divided by '/')
Apply link to each piece
I don't think the string manipulation you want to do is possible from the template side. I think a possible way is using a custom template filter that receives request.path and returns a list of tuples (link, text) and then iterate over that list on the template side and create the breadcrumbs.
https://docs.djangoproject.com/en/1.9/howto/custom-template-tags/#writing-custom-template-filters

Paginated based on the alphabet (A-Z)

I have a simple contacts application where I want to paginate the contact list based on first name alphabet.
Here is my views.py
def contacts(request):
contact_list = Contact.objects.filter(user=request.user).order_by('first_name')
return render(request, 'contact/contact.html', {'contact_list': contact_list})
Here is my template
<ul>
{% for contact in contact_list %}
<li>{{ contact.first_name }}</li>
{% endfor %}
</ul>
Is there a default way in Django that does this? There is Django pagination but I think that only splits data across pages. What would be the easiest way to do so?
It seems a letter-wise paginator does not exist by default. Pages like https://djangosnippets.org/snippets/1364/ <<< this one show hand-made implementations.
However, it's not so hard to implement: you can base yourself on startswith keyword and:
pages = [myQuerySet.filter(myfield__istartswith=i) for i in "ABC...XYZ"] #full alphabet here
(let myQuerySet be, actually, contact_list; let myfield be, actually, first_name).
I've done this once, by adding a letter field to my model and "paginating" manually. This raised a lot of interesting situation with foreign alphabets. Found this useful: https://pypi.python.org/pypi/Unidecode
Didn't find any "smarter" way to go about it. But I'd be interested in hearing about more "plug-n-play" solution...

if condition in template to display link in django

In my django app's index.html (which I consider as the home page of the site)I am giving links to various locations in the website.When the user reaches one of the locations,he should find a link there, to get back to the home page.So I created a base.html to be inherited by all the pages including index.html.In the base.html,I am providing these links.
base.html
...
Archives
<br/>
Reports
<br/>
Home
<br/>
..
My problem is that ,when I am on index page(home) ,I don't want to display the home link.Is this possible to do so in the template,using an {% if %} condition?
Currently I am not passing any parameter in the view
#login_required
def index(request, template_name):
print 'index()::template=',template_name
return custom_render(request, {},template_name )
def custom_render(request,context,template):
req_context=RequestContext(request,context)
return render_to_response(template,req_context)
Firstly, you can use the django render shortcut to avoid having to use the long-winded custom_render.
from django.shortcuts import render
#login_required
def index(request, template_name):
return render(request, template_name,extra={})
You can be cheeky and in your base.html do something like:
{% url home as home_url %}
{% if request.path != home_url %}Home{% endif %}
to quickly check if the current page is the home page.
If it might get more complicated in the future, you can use a template tag to check whether or not the current URL you are on matches another URL. Here is a template tag I have used before to check if a menu link is currently active:
https://gist.github.com/2049936
This isn't exactly what you asked for, but an alteratively way to do this which I often much prefer is to use JavaScript to either hide or change the color of links to the current page. For example, if you were using jQuery:
// Assumes relative paths in a elements
$('a[href="' + window.location.pathname + '"]').each(function (index, element) {
$(element).addClass('someClass');
});
someClass could be a CSS rule to set the 'display' attribute of that element to 'none', or to simply make the link look like plain text, and behave like plain text when mousing over or clicking on it.
This has two possible advantages:
it prevents your template from becoming too convoluted, and from being difficult to maintain if you start arbitrarily adding nav elements
you have the ability to keep your nav consistent between pages, which in my opinion is a good design decision
It's no silver bullet, but I think it's important to recognise that sometimes these things aren't necessarily best done in templates. I think of my django templates first and foremost as a way of structuring data. There will always be some element of presentation in them, but I try to remove that as much as possible. Others will disagree.

Python / Django - Get List Value With Index From Object Variable Value

I have a list that is passed into a template. I want to access a value with a specific index. Problem is the list is accessed with dot notation in the template...
For example:
object = { id: 1 }
list = [ "zero", "one" ]
print list[ object.id ] ## one
Once the list is in the template you access values by index with dot notation.
list.1 ## one
list[ object.id ] ## this doesn't work
list.object.id ## this doesn't work obv.
How can I access the value "one" with the index of "1"?
Thanks in advance!
I don't think this is possible with Django's template language. It is pretty limited by design.
You can do this by putting that code in the view, and passing the value of list[object.id] down to the template when you render it.
I don't quite agree it's impossible.
You can create template tag, which will accept two arguments and will inject a new
variable into a template context.
The usage can look as follows:
{% get_list_member list object.id as list_member %}
then you can use list_member as ordinary template variable {{ list_member }}
check the implementation of standard url template tag, which also allows to assign url into
template context variable for later use.

Categories