Accessing dict elements with leading underscores in Django Templates - python

I am trying to access elements of a dict with keys that start with the underscore character. For example:
my_dict = {"_source": 'xyz'}
I'm trying to access them in a Django template. Obviously I realise that you can't access underscored python variables from a Django template (because they are considered private in Python) but this is a dict object where any immutable object is a valid key.
I can't access the above dict in a Django template using {{ my_dict._source }} so I assume Django is preventing it. Is that accurate?
I am kind of hoping Django does something sane with variables that start with underscore like still doing dict lookups (the first thing is supposedly tries) but refuses to do attribute lookups, method calls and list index lookups since an underscored prefixed variable would be invalid. I am quickly loosing hope though.
For the record, I know someone will suggest to just change the dict but this is actually a multi-levelled dictionary returned by the rawes library when executing REST API request on a ElasticSearch instance.

The docs mention that you can't have a variable start with an underscore:
Variable names must consist of any letter (A-Z), any digit (0-9), an underscore (but they must not start with an underscore) or a dot.
but you can easily write a custom template filter to mimic the dictionary's get method:
#register.filter(name='get')
def get(d, k):
return d.get(k, None)
and
{{ my_dict|get:"_my_key" }}

In my case, if I know the dict elements, and it's only one, I prefer to rename the dict key using pop:
my_dict['new_key'] = my_dict.pop('_old_key')
That way I get a new name on the dict, and I can access in the template without problems.

Related

Permanently replace value in Django

After extensive googling, I still havent come up with an effecient way to solve this.
Im creating a website using Django. I have a db which contains time data, more specifically dates. The value for "the present" is set to 3000-01-01 (YYYY-MM-DD) as is common practice for time-querying.
What I want to do is display a string like "Now" or "Present" or any other value instead of the date 3000-01-01. Is there some sort of global override anywhere that I can use? Seems like a waste to hard-code it in every view/template.
Cheers!
Since this is rendering, I would advice against "subclassing" the DateField such that it renders 'now' instead of the original date(..) object: it will make calculations in the model layer more cumbersome.
Probably a good way to deal with this is implementing a template filter [Django-doc], for example we can construct a file:
# app/templatetags/nowdate.py
from django import template
register = template.Library()
PRESENT = date(3000, 1, 1)
#register.filter
def nowdate(value):
if value == PRESENT:
return 'present'
return value
The templatetags directory of the app application, needs to contain an __init__.py file as well (an empty file), and the app of course needs to be part of the INSTALLED_APPS in the settings.py.
Then we can use it in the template like:
<!-- app/templates/app/some_template.html -->
{{ some_model.some_date_field|nowdate }}
Here we thus fetch the some_date_field of the some_model variable (this attribute is thus a date(..) object), and we pass it through the nowdate filter we have constructed such that, if it is 3000-01-01, it is replaced by the 'present' string.
The advantage here is that if we later change our mind about what date the "present" is, we can easily change it in the template filter, furthermore we can easily extend it, for example by adding a 'past', 'future', etc.

Django template cannot access JSON Key in duplicate quotations: {" 'Key' ": " Value "}

My Django app is interacting with an API and displaying results in the templates.
The API result has some normal Key Value pairs and some custom fields which have a Key in double and single quotations.
The key is formatted as " 'custom_field_123' " in the result JSON:
{'cost_price': '0.00', "'asset_field_1234'": None, "'asset_field_5768'": None}
I know this isn't correct JSON format but it's what I have to deal with.
In the Django templates I can use:
<p>{{tower.name}}</p>
for regular format keys.
But the template language will not recognize:
<p>{{tower.'custom_field_123'}}</p>
Or
<p>{{tower.('custom_field_123')}}</p>
Is there a way to access these values or will I have to rename the keys in quotations to access them in the template.
From the template reference docs:
Variable names must consist of any letter (A-Z), any digit (0-9), an underscore (but they must not start with an underscore) or a dot.
So quotes aren't allowed, and the template language has no way to directly access those properties.
You could write your own template tag to look up dictionary items by a variable key (as in this question) but I would suggest fixing your data.

Django interpreting dict values ambiguously [duplicate]

In a Django view you can access the request.GET['variablename'], so in your view you can do something like this:
myvar = request.GET['myvar']
The actual request.GET['myvar'] object type is:
<class 'django.http.QueryDict'>
Now, if you want to pass multiple variables with the same parameter name, i.e:
http://example.com/blah/?myvar=123&myvar=567
You would like a python list returned for the parameter myvar, then do something like this:
for var in request.GET['myvar']:
print(var)
However, when you try that you only get the last value passed in the url i.e in the example above you will get 567, and the result in the shell will be:
5
6
7
However, when you do a print of request.GET it seems like it has a list i.e:
<QueryDict: {u'myvar': [u'123', u'567']}>
Ok Update:
It's designed to return the last value, my use case is i need a list.
from django docs:
QueryDict.getitem(key)
Returns
the value for the given key. If the
key has more than one value,
getitem() returns the last value. Raises
django.utils.datastructures.MultiValueDictKeyError
if the key does not exist. (This is a
subclass of Python's standard
KeyError, so you can stick to catching
KeyError
QueryDict.getlist(key) Returns the
data with the requested key, as a
Python list. Returns an empty list if
the key doesn't exist. It's guaranteed
to return a list of some sort.
Update:
If anyone knows why django dev's have done this please let me know, seems counter-intuitive to show a list and it does not behave like one. Not very pythonic!
You want the getlist() function of the GET object:
request.GET.getlist('myvar')
Another solution is creating a copy of the request object... Normally, you can not iterate through a request.GET or request.POST object, but you can do such operations on the copy:
res_set = request.GET.copy()
for item in res_set['myvar']:
item
...
When creating a query string from a QueryDict object that contains multiple values for the same parameter (such as a set of checkboxes) use the urlencode() method:
For example, I needed to obtain the incoming query request, remove a parameter and return the updated query string to the resulting page.
# Obtain a mutable copy of the original string
original_query = request.GET.copy()
# remove an undesired parameter
if 'page' in original_query:
del original_query['page']
Now if the original query has multiple values for the same parameter like this:
{...'track_id': ['1', '2'],...} you will lose the first element in the query string when using code like:
new_query = urllib.parse.urlencode(original_query)
results in...
...&track_id=2&...
However, one can use the urlencode method of the QueryDict class in order to properly include multiple values:
new_query = original_query.urlencode()
which produces...
...&track_id=1&track_id=2&...

How do I access dictionary keys that contain hyphens from within a Django template?

We have a system built on a custom database, where many of the attributes are named containing hyphens, ie:
user-name
phone-number
These properties cannot be accessed in templates as follows:
{{ user-name }}
Django throws an exception for this. I'd like to avoid having to convert all of the keys (and sub-table keys) to use underscores just to work around this. Is there an easier way?
A custom template tag is probably the only way to go here if you don't want to restructure your objects. For accessing dictionaries with an arbitrary string key, the answer to this question provides a good example.
For the lazy:
from django import template
register = template.Library()
#register.simple_tag
def dictKeyLookup(the_dict, key):
# Try to fetch from the dict, and if it's not found return an empty string.
return the_dict.get(key, '')
Which you use like so:
{% dictKeyLookup your_dict_passed_into_context "phone-number" %}
If you want to access an object's attribute with an arbitrary string name, you could use the following:
from django import template
register = template.Library()
#register.simple_tag
def attributeLookup(the_object, attribute_name):
# Try to fetch from the object, and if it's not found return None.
return getattr(the_object, attribute_name, None)
Which you would use like:
{% attributeLookup your_object_passed_into_context "phone-number" %}
You could even come up with some sort of string seperator (like '__') for subattributes, but I'll leave that for homework :-)
Unfortunately, I think you may be out of luck. From the docs:
Variable names must consist of any letter (A-Z), any digit (0-9), an
underscore or a dot.
OrderedDict dictionary types support dashes:
https://docs.python.org/2/library/collections.html#ordereddict-objects
This seems to be a side effect of the implementation of OrderedDict. Notice below that the key value pairs are actually passed in as sets. I would bet that the implementation of OrderedDict doesn't use the "key" passed in the set as a true dict key thus getting around this issue.
Since this is a side-effect of the implementation of OrderedDict, it may not be something you want to rely on. But it works.
from collections import OrderedDict
my_dict = OrderedDict([
('has-dash', 'has dash value'),
('no dash', 'no dash value')
])
print( 'has-dash: ' + my_dict['has-dash'] )
print( 'no dash: ' + my_dict['no dash'] )
Result:
has-dash: has dash value
no dash: no dash value

Template strings python 2.5 error

#!/usr/bin/python
from string import Template
s = Template('$x, go home $x')
s.substitute(x='lee')
print s
error i get is
<string.Template object at 0x81abdcc>
desired results i am looking for is : lee, go home lee
You need to look at the return value of substitute. It gives you the string with substitutions performed.
print s.substitute(x='lee')
The template object itself (s) is not changed. This gives you the ability to perform multiple substitutions with the same template object.
You're not getting an error: you're getting exactly what you're asking for -- the template itself. To achieve your desired result,
print s.substitute(x='lee')
Templates, like strings, are not mutable objects: any method you call on a template (or string) can never alter that template -- it can only produce a separate result which you can use. This, of course, applies to the .substitute method. You're calling it, but ignoring the result, and then printing the template -- no doubt you expect the template itself to be somehow altered, but that's just not how it works.
print s.substitute(x='lee')

Categories

Resources