Django dynamic template variable inside if clause - django

Here's what I'm trying to achieve in "pseudo code":
{% for page in pages %}
{% if 'can_access_page_{{page.name}}' in perms %}
<li>
{{ page.name }}
</li>
{% endif %}
{% endfor %}
How to do this? Permission names I can customize — but still can't figure out this one.

Simplest way is to slightly abuse Django's existing add template filter (intended for numbers but works for strings), as in this answer:
https://stackoverflow.com/a/4524851/202168

You'll need a custom filter. Something like:
#register.filter
def check_page_perms(page, perms):
return 'can_access_page_%s' % page.name in perms
and use it:
{% if page|check_page_perms:perms %}

Related

How to acess form based on index django

I am trying to access the form based on the index value how can i do that exactly?
Ex:
{% for line in data_lines %}
{{line}}
{% with x=forloop.counter %}
{{form.x}}
{% endwith %}
{% endfor %}
As Django discourages adding too much logic hence I don't think it's possible using built-in Django Template features. You can achieve this by sending a dict instead of data_lines and accessing via key, value as:
{% for key, value in data_lines.items %}
{{value}}
{{ form.key }}
{% endfor %}
If you really want it then you could write a custom template filter.

getting multiple paginator

If I include paginator, then its printing multiple paginator on same page. because I am including in forloop. How do I solve this problem? please help
----------------------
{% autopaginate recipes %}
{% for recipe in recipes %}
{{ forloop.counter }}
{% endfor %}
-----------
here is my full code.
{% with followers=current_user.get_profile.get_following.all %}
{% for follower in followers %}
{% with recipes=follower.recipe_set.all %}
{% for recipe in recipes %}
{{ forloop.counter }}
{% endfor %}
{% endwith %}
{% endfor %}
{% endwith %}
Result - > 1 2 3 1 2 3 ...... 50. It should be 53. So I can easily use paginator
thanks
the doc string in the setup.py file of django-pagination mentions the below,
Decide on a variable that you would like to paginate, and use the autopaginate tag on that variable before iterating over it. This
could take one of two forms (using the canonical object_list
as an example variable):
{% autopaginate object_list %}
This assumes that you would like to have the default 20 results per page. If you would like to specify your own amount of
results per page, you can specify that like so:
`{% autopaginate object_list 10 %}`
Note that this replaces object_list with the list for the current page, so you can iterate over the object_list like you normally would.
Now you want to display the current page and the available pages, so somewhere after having used autopaginate, use the paginate
inclusion tag:
{% paginate %}
This does not take any arguments, but does assume that you have already called autopaginate, so make sure to do so first.
That's it! You have now paginated object_list and given users of
the site a way to navigate between the different pages--all without
touching your views.
So, where are you using paginate tag after the autopaginate? You actually need not loop through recipes, autopaginate should do that for you wherever you call paginate.

Django template - set variable in for loop

I am using this code in my templatetags:
http://pastie.org/3530409
And I know for context problem and bad design (that this logic should not be in view) but I need in template solution for this:
{% for tag in page.tagname_list %}
{% ifequal tag "wiki" %}
{% set howto = 1 %}
{% endifequal %}
{% endfor %}
So I can use howto variable latter for my view logic.
Is there any way to do this in view templates, without model modification ?
If answer yes, please provide some solution...
Thanks a lot.
Instead of having to set the variable, you could just do:
{% if "wiki" in page.tagname_list %}
# do your wiki stuff below.
{% endif %}

Django template for loop. Member before

I want to create such loop:
{% for object in objects %}
{% if object.before != object %}
{{ object }} this is different
{% else %}
{{ object }} this is the same
{% endfor %}
Based on https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#for I can't. Is there really no simple way to do this? Or I just need to use counter and check for objects[counter-1]?
P.S. .before is theoretical and objects is simple query list. I want to take and do something with the loop member that encountered before current loop member.
Check ifchanged template tag
There is a "simple way" to do this: write a custom template tag. They're really not hard. This would probably do the trick (untested):
#register.simple_tag
def compare_objects(object_list):
comparisons = []
for i in range(1, len(object_list)):
if object_list[i] > object_list[i-1]:
comparisons.append('bigger')
else:
comparisons.append('smaller')
return comparisons
The built-in template tags and filters don't make it easy (as of Django 1.4), but it is possible by using the with tag to cache variables and the add, slugify, and slice filters to generate a new list with only one member.
The following example creates a new list whose sole member is the previous member of the forloop:
{% for item in list %}
{% if not forloop.first %}
{% with forloop.counter0|add:"-1" as previous %}
{% with previous|slugify|add:":"|add:previous as subset %}
{% with list|slice:subset as sublist %}
<p>Current item: {{ item }}</p>
<p>Previous item: {{ sublist.0 }}</p>
{% endwith %}
{% endwith %}
{% endwith %}
{% endif %}
{% endfor %}
This isn't an elegant solution, but the django template system has two faults that make this hack unavoidable for those who don't what to write custom tags:
Django template syntax does not allow nested curly parenthesis. Otherwise, we could do this:
{{ list.{{ forloop.counter|add:-1 }} }}
The lookup operator does not accept values stored using with (and perhaps for good reason)
{% with forloop.counter|add:-1 as index %}
{{ list.index }}
{% endwith %}
This code should work just fine as a django template, as long as object has a property or no-argument method called before, and objects is iterable (and '<' is defined).
{% for object in objects %}
{% if object.before < object %}
this is bigger
{% else %}
this is smaller
{% endfor %}

Django Many to Many in template

This is my template tag in a forloop
{{ product.feature_set.all.1.value }}
i want to change the number 1 to the forloop.counter. is this posible?
like:
{{
product.feature_set.all.forloop.counter.value
}}
It does not work like that, but is there a way to do this?
This doesn't make sense. You should be looping through the queryset itself.
{% for feature in product.feature_set.all %}
{{ feature }}
{% endfor %}
Since #Daniel's answer doesn't satisfy you, I thought you might want to try writing a custom filter. Here is a rough draft:
#register.filter
def custom_m2m(queryset, forloop_counter):
return queryset[forloop_counter].value
You can use it in your template like this:
{% for ... %}
{{ product.feature_set.all|custom_m2m:forloop.counter }}
{% endfor %}