Good Afternoon,
How can I use a variable variable name in Django templates?
I have a custom auth system using context, has_perm checks to see if the user has access to the specified section.
deptauth is a variable with a restriction group name i.e SectionAdmin. I think has.perm is actually checking for 'deptauth' instead of the variable value SectionAdmin as I would like.
{%if has_perm.deptauth %}
How can I do that? has_perm.{{depauth}} or something along those lines?
EDIT - Updated code
{% with arg_value="authval" %}
{% lookup has_perm "admintest" %}
{% endwith %}
{%if has_perm.authval %}
window.location = './portal/tickets/admin/add/{{dept}}/'+val;
{% else %}
window.location = './portal/tickets/add/{{dept}}/'+val;
{%endif%}
has_perm isn't an object.. it's in my context processor (permchecker):
class permchecker(object):
def __init__(self, request):
self.request = request
pass
def __getitem__(self, perm_name):
return check_perm(self.request, perm_name)
You're best off writing your own custom template tag for that. It's not difficult to do, and normal for this kind of situation.
I have not tested this, but something along these lines should work. Remember to handle errors properly!
def lookup(object, property):
return getattr(object, property)()
register.simple_tag(lookup)
If you're trying to get a property rather than execute a method, remove those ().
and use it:
{% lookup has_perm "depauth" %}
Note that has_perm is a variable, and "depauth" is a string value. this will pass the string for lookup, i.e. get has_perm.depauth.
You can call it with a variable:
{% with arg_value="depauth_other_value" %}
{% lookup has_perm arg_value %}
{% endwith %}
which means that the value of the variable will be used to look it up, i.e. has_perm.depauth_other_value'.
You can try like this,
{{ dict|key:key_name }}
Filter:
def key(d, key_name):
return d[key_name]
key = register.filter('key', key)
More information, django ticket
Related
Hi I want to check if my variable is numeric in Django template
and I tried this code
{% if isnumeric(item) %}
<h1>{{item}}</h1>
{% endif %}
but this throws me this error
Could not parse the remainder: '(item)' from 'isnumeric(item)'
I tried to find a builtin template tag or filter in this page
https://docs.djangoproject.com/en/3.1/ref/templates/builtins/ of Django document
and I searched for this question in StackOverflow too
but I did not found anything related
I don't believe there's a built in template function to check for that. One way to do it is to write your own:
https://docs.djangoproject.com/en/3.1/howto/custom-template-tags/
The code would look something like:
my_filters.py
from django import template
register = template.Library()
#register.filter()
def is_numberic(value):
return value.isdigit()
And in the html:
{% load my_filters %}
{% if item|is_numeric %}
...
isnumeric() python fuction doesn't take any parameters
Make a fuction in your model:
def isnumeric(self):
item = self.item
if item.isnumeric() is True:
return True
else:
return False
then in your template:
{% if item.isnumeric %}
<h1>{{item}}</h1>
{% endif %}
With this, you can use the isnumeric() function in your template. You can add an else statement too.
Take a look to isnumeric() function
I am new to coding and new to Django. I searched stackoverflow for my question but didn't find what I was looking for:
What I am trying to do is check if certain values are in my database and if yes, pass it as a variable to the template. The values will be items of a dropdown menu.
If I have for example a database with bicycle1 to bicycleN I'd like to check if the value of the attribute "handlebar" of each database-object matches a certain manufacturer. If yes, pass it to the template so it can appear in the dropdown menu to later filter the results.
First I thought I should check in the template itself and thought about something like this:
bicyle_list.html
<ul id='dropdown1' class='dropdown-content'>
{% for bicyle in bicycles %}
{% with manufacturerA=False %}
{% if manufacturerA == False and bicycle.handlebar == "manufacturerA" %}
<li>ManufacturerA</li>
{% manufacturerA=True %}
{% endif %}
{% endwith %}
{% endfor %}
But as I understand the template should only contain rendering logic. (Besides, I`d have to use boolean variables in the for-loop, because a manufacturer should only appear once in the dropdown menu even if there are several bicycles with that certain handlebar. Changing the value of variables in a template seems quite complicated to me.)
In the views.py I thought about this but don't know how to work with conditions and the rendering-method:
views.py
bicycles = Bicycle.objects.all()
for bicycle in bicyles:
if bicycle.handlebar == "manufacturerA":
manufacturerA= "manufacturerA"
if bicycle.handlebar == "manufacturerB":
manufacturerB= "manufacturerB"
#if variable manufacturerA exists, pass it to the template – if not, not! Same with manufacturerB
#But how to include in return render(..)?
return render(request, 'shop/bicycle_list.html', {'bicycles': bicycles})
Do you have any idea how to pass optional variables?
You can obtain a list of distinct manufacturers with:
def some_view(request):
manufacturers = Bicycle.objects.values_list('handlebar', flat=True).distinct()
return render(request, 'shop/bicycle_list.html', {'manufacturers': manufacturers})
<ul id='dropdown1' class='dropdown-content'>
{% for manufacturer in manufacturers %}
<li>{{ manufacturer }}</li>
{% endfor %}
</ul>
You however might want to make a model for the manufacturer, and work with a many-to-one relationship [Django-doc].
I have been working on this for two day, and have read almost every example on stackoverflow and consulted the django documentation. I am trying to pass my dict from the views.py to my template, but I keep getting the stupid "Could not parse the remainder" error. I'm not doing anything fancy. Just Href buttons passing in a parameter to represent what that button is. Then a template page opens using that parameter as a string to make the new page and url unique.
pass in with:
Call
urls.py
urlpatterns = [
url(r'^call=(\d+)/$', views.call, name='call')
]
views.py
def call(request, callID):
call_id = { 'id':callID }
return render(request, 'site/call.html', call_id)
Call template
{% extends 'site/layout.html' %}
{% block content %}
{% with call_id.get('id') as view_id %}
<h3 class="center-align blue lighten-3">Site # Room {{ view_id }}</h3>
Cancel
{% endwith %}
{% endblock %}
I have tried request.GET.get('id') and a bizillion other things. Can someone show me how I can actually parse those dict values I passed in?
You're not actually passing a dictionary at all. You're passing a single value, id, so you should just use that. And there is no need for any with block.
Site # Room {{ id }}
I have a variable that I'm pulling into a table that sometimes is a date and sometimes is a string. If the variable is a date, I want to change the formatting:
<td>{{ action.extra_column|date:"M d" }}</td>
But if it is a string, I just want to display it as is:
<td>{{ action.extra_column }}</td>
If I try to format it and it is a string, I get no output for the variable.
How can I determine the type so that I can adjust my rendering based on type.
You could also implement a general template filter as an equivalent to the type() builtin:
# app/templatetags/util.py
from django import template
register = template.Library()
#register.filter
def get_type(value):
return type(value)
# template.html
{% load util %}
{% if extra_column|get_type == 'str' %}
String
{% elif extra_column|get_type == 'datetime.date' %}
Date
{% else %}
Oh no!
{% endif %}
I think Ignacio and Dirk are right, however. Can't you just have two keys (you say "array", but I assume you mean "dictionary" from the fact that the items have names) called date and detail?
# views.py
...
actions = [{
'some_property': 'some_value'
'date': None,
'detail': 'details'
},
{
'some_property': 'some_value'
'date': datetime.date.today(),
'detail': None
}]
...
# template.html
{% for action in actions %}
<td>{% if action.date %}{{ action.date|date:"M d" }}{% endif %}{{ action.detail }}</td>
{% endfor %}
# output
<td>details</td>
<td>Aug 19</td>
Like Ignacio Vazquez-Abrams pointed out in the first comment, that's not really a great way to code your logic. I would ensure that your variable has a certain type. That could be solved through an additional variable you add to the context or an object that holds the data and something that describes the type of data.
If you want to stick to your logic, a possible approach would be to write your own template filter (let's call it date_or_string). The filter could subclass the builtin date filter with the format parameter being optional. In case the parameter is passed it works like the normal date filter, without the parameter it simply returns the string. In a more complex scenario the filter could also do some type checking. Just an idea, i wouldn't actually put that kind of logic into the template.
I know I'm way behind on this (by three years) but I just got here looking to do something similar and came up with what I think is a decent solution.
Just add a function to your models like get_model_type and have it return something you'd expect from each model like so:
class MyModelOne(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
first_name = models.CharField(max_length=255)
def get_model_type(self):
return "my_model_one"
class MyModelTwo(models.Model):
date_created = models.DateTimeField(auto_now_add=True)
other_field = models.CharField(max_length=255)
def get_model_type(self):
return "my_model_two"
Then in your template you can easily just call that function:
{% if model.get_model_type == 'my_model_one' %}
<p>Model One</p>
{% elif model.get_model_type == 'my_model_two' %}
<p>Model Two</p>
{% endif %}
Late to the party, but I just had this problem. The solution I went for is duck-typing, so:
{% if action.extra_column.year %}
{{ action.extra_column|date:"M y" }}
{% else %}
{{ action.extra_column }}
{% endif %}
Could you argue that this is definitely not the right way to do it? Probably. Will it get the job done without writing your own template filter and having even more code to maintain? Absolutely.
That's my approach:
#register.filter
def get_type(value):
""" It returns variable type as a pure string name """
return type(value).__name__
You can try this to recognize String vs List type:
{%if v_1.0.1|length == 0%}
<!--STR-->
{{v_1}}
{%else%}
<!--List-->
{{v_1.0}}
{%endif%}
I'm implementing a custom permissions application in my Django project, and I'm lost as to how to implement a custom template tag that checks a logged in user's permissions for a specific object instance and shows a piece of HTML based on the outcome of the check.
What I have now is (pseudocode):
{% check_permission request.user "can_edit" on article %}
<form>...</form>
{% endcheck %}
('check_permission' is my custom template tag).
The templatetag takes in the user, the permission and the object instance and returns the enclosed HTML (the form). This currently works fine.
What I would like to do however, is something like:
{% if check_permission request.user "can_edit" on article %}
<form>...</form>
{% else %}
{{ article }}
{% endif %}
I've read about the assignment tag, but my fear is that I would pollute the context variable space with this (meaning I might overwrite previous permission context variables). In other words, as the context variables are being defined on different levels (the view, middleware in my case, and now this assignment template tag), I'm worried about maintainability.
You can use template filters inside if statements. So you could rewrite your tag as a filter:
{% if request.user|check_can_edit:article %}
Note that it's tricky to pass multiple arguments of different types to a filter, so you'll probably want to use one filter per permission, above I've used check_can_edit.
You can definitely do that if you're willing to write some more lines of python code to improve your template readability! :)
You need to parse the tag content yourself, even the parameters it takes and then resolve them, if you want to use variables on them.
The tag implemented below can be used like this:
{% load mytag %}
{% mytag True %}Hi{% else %}Hey{% endmytag %} Bro
Or with a variable:
{% mytag myobject.myflag %}Hi{% else %}Hey{% endmytag %} Bro
So, here's the way I did it:
from django.template import Library, Node, TemplateSyntaxError
register = Library()
#register.tag
def mytag(parser, token):
# Separating the tag name from the "test" parameter.
try:
tag, test = token.contents.split()
except (ValueError, TypeError):
raise TemplateSyntaxError(
"'%s' tag takes two parameters" % tag)
default_states = ['mytag', 'else']
end_tag = 'endmytag'
# Place to store the states and their values
states = {}
# Let's iterate over our context and find our tokens
while token.contents != end_tag:
current = token.contents
states[current.split()[0]] = parser.parse(default_states + [end_tag])
token = parser.next_token()
test_var = parser.compile_filter(test)
return MyNode(states, test_var)
class MyNode(Node):
def __init__(self, states, test_var):
self.states = states
self.test_var = test_var
def render(self, context):
# Resolving variables passed by the user
test_var = self.test_name.resolve(context, True)
# Rendering the right state. You can add a function call, use a
# library or whatever here to decide if the value is true or false.
is_true = bool(test_var)
return self.states[is_true and 'myvar' or 'else'].render(context)
And that's it. HTH.
In Django 2 the assignment tag was replaced by simple_tag() but you could store the custom tag result as a template variable:
# I'm assuming that check_permission receives user and article,
# checks if the user can edit the article and return True or False
{% check_permission user article as permission_cleared %}
{% if permission_cleared %}
<form>...</form>
{% else %}
{{ article }}
{% endif %}
Check the current doc about custom template tags: https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/#simple-tags
inside my_tags.py
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def make_my_variable_true(context):
context['my_variable'] = True
return '' # without this you'll get a "None" in your html
inside my_template.html
{% load my_tags %}
{% make_my_variable_true %}
{% if my_variable %}foo{% endif %}
In this case best solution is to use custom filter. If you don't want write long code for custom tag. Also if you don't want to copy/paste others code.
Here is an example
Inside templatetag
register = template.Library()
def exam_available(user, skill):
skill = get_object_or_404(Skill, id=skill)
return skill.exam_available(user)
register.filter('exam_available', exam_available)
Inside template
{{ request.user|exam:skill.id }}
or
{% if request.user|exam:skill.id %}
Since one of the main common of it is to use request.user or any specific object(id) inside model's custom method, so filtering that individual object or user is the easiest way to make it done. :)