Advanced functions in Django templates? - python

I need to add a <br/> after each character in a string which I'm passing into the template. While one way of doing it would involve doing it before it is passed into the template (i.e. in the Python code), I'm wondering if it is possible to do it in the actual template.
Or would I be better off creating a helper function and invoking it from the template, and if so, how would I import that function/module into the template.
The one thing I want to avoid is mixing HTML bits with the view code so adding the <br/>s in the view should only be the last resort.

Strings in Python are sequences, therefore the individual characters in them can be joined.

How about you make such a function in the javascript, and after passing the string to the template, instead of using it directly, you can call that function on the string, and the function returns the string with every character is followed by a <br/>?
var nStr = "";
for (i=0;i<str.length;i++)
{
nStr = nStr.concat(str.charAt(i),"<br/>");
}

Related

why there is space for "?" in the code. How to remove it? [duplicate]

I would like to put an int into a string. This is what I am doing at the moment:
num = 40
plot.savefig('hanning40.pdf') #problem line
I have to run the program for several different numbers, so I'd like to do a loop. But inserting the variable like this doesn't work:
plot.savefig('hanning', num, '.pdf')
How do I insert a variable into a Python string?
See also
If you tried using + to concatenate a number with a string (or between strings, etc.) and got an error message, see How can I concatenate str and int objects?.
If you are trying to assemble a URL with variable data, do not use ordinary string formatting, because it is error-prone and more difficult than necessary. Specialized tools are available. See Add params to given URL in Python.
If you are trying to assemble a SQL query, do not use ordinary string formatting, because it is a major security risk. This is the cause of "SQL injection" which costs real companies huge amounts of money every year. See for example Python: best practice and securest way to connect to MySQL and execute queries for proper techniques.
If you just want to print (output) the string, you can prepare it this way first, or if you don't need the string for anything else, print each piece of the output individually using a single call to print. See How can I print multiple things (fixed text and/or variable values) on the same line, all at once? for details on both approaches.
Using f-strings:
plot.savefig(f'hanning{num}.pdf')
This was added in 3.6 and is the new preferred way.
Using str.format():
plot.savefig('hanning{0}.pdf'.format(num))
String concatenation:
plot.savefig('hanning' + str(num) + '.pdf')
Conversion Specifier:
plot.savefig('hanning%s.pdf' % num)
Using local variable names (neat trick):
plot.savefig('hanning%(num)s.pdf' % locals())
Using string.Template:
plot.savefig(string.Template('hanning${num}.pdf').substitute(locals()))
See also:
Fancier Output Formatting - The Python Tutorial
Python 3's f-Strings: An Improved String Formatting Syntax (Guide) - RealPython
With the introduction of formatted string literals ("f-strings" for short) in Python 3.6, it is now possible to write this with a briefer syntax:
>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'
With the example given in the question, it would look like this
plot.savefig(f'hanning{num}.pdf')
plot.savefig('hanning(%d).pdf' % num)
The % operator, when following a string, allows you to insert values into that string via format codes (the %d in this case). For more details, see the Python documentation:
printf-style String Formatting
You can use + as the normal string concatenation function as well as str().
"hello " + str(10) + " world" == "hello 10 world"
In general, you can create strings using:
stringExample = "someString " + str(someNumber)
print(stringExample)
plot.savefig(stringExample)
If you would want to put multiple values into the string you could make use of format
nums = [1,2,3]
plot.savefig('hanning{0}{1}{2}.pdf'.format(*nums))
Would result in the string hanning123.pdf. This can be done with any array.
Special cases
Depending on why variable data is being used with strings, the general-purpose approaches may not be appropriate.
If you need to prepare an SQL query
Do not use any of the usual techniques for assembling a string. Instead, use your SQL library's functionality for parameterized queries.
A query is code, so it should not be thought about like normal text. Using the library will make sure that any inserted text is properly escaped. If any part of the query could possibly come from outside the program in any way, that is an opportunity for a malevolent user to perform SQL injection. This is widely considered one of the important computer security problems, costing real companies huge amounts of money every year and causing problems for countless customers. Even if you think you know the data is "safe", there is no real upside to using any other approach.
The syntax will depend on the library you are using and is outside the scope of this answer.
If you need to prepare a URL query string
See Add params to given URL in Python. Do not do it yourself; there is no practical reason to make your life harder.
Writing to a file
While it's possible to prepare a string ahead of time, it may be simpler and more memory efficient to just write each piece of data with a separate .write call. Of course, non-strings will still need to be converted to string before writing, which may complicate the code. There is not a one-size-fits-all answer here, but choosing badly will generally not matter very much.
If you are simply calling print
The built-in print function accepts a variable number of arguments, and can take in any object and stringify it using str. Before trying string formatting, consider whether simply passing multiple arguments will do what you want. (You can also use the sep keyword argument to control spacing between the arguments.)
# display a filename, as an example
print('hanning', num, '.pdf', sep='')
Of course, there may be other reasons why it is useful for the program to assemble a string; so by all means do so where appropriate.
It's important to note that print is a special case. The only functions that work this way are ones that are explicitly written to work this way. For ordinary functions and methods, like input, or the savefig method of Matplotlib plots, we need to prepare a string ourselves.
Concatenation
Python supports using + between two strings, but not between strings and other types. To work around this, we need to convert other values to string explicitly: 'hanning' + str(num) + '.pdf'.
Template-based approaches
Most ways to solve the problem involve having some kind of "template" string that includes "placeholders" that show where information should be added, and then using some function or method to add the missing information.
f-strings
This is the recommended approach when possible. It looks like f'hanning{num}.pdf'. The names of variables to insert appear directly in the string. It is important to note that there is not actually such a thing as an "f-string"; it's not a separate type. Instead, Python will translate the code ahead of time:
>>> def example(num):
... return f'hanning{num}.pdf'
...
>>> import dis
>>> dis.dis(example)
2 0 LOAD_CONST 1 ('hanning')
2 LOAD_FAST 0 (num)
4 FORMAT_VALUE 0
6 LOAD_CONST 2 ('.pdf')
8 BUILD_STRING 3
10 RETURN_VALUE
Because it's a special syntax, it can access opcodes that aren't used in other approaches.
str.format
This is the recommended approach when f-strings aren't possible - mainly, because the template string needs to be prepared ahead of time and filled in later. It looks like 'hanning{}.pdf'.format(num), or 'hanning{num}.pdf'.format(num=num)'. Here, format is a method built in to strings, which can accept arguments either by position or keyword.
Particularly for str.format, it's useful to know that the built-in locals, globals and vars functions return dictionaries that map variable names to the contents of those variables. Thus, rather than something like '{a}{b}{c}'.format(a=a, b=b, c=c), we can use something like '{a}{b}{c}'.format(**locals()), unpacking the locals() dict.
str.format_map
This is a rare variation on .format. It looks like 'hanning{num}.pdf'.format_map({'num': num}). Rather than accepting keyword arguments, it accepts a single argument which is a mapping.
That probably doesn't sound very useful - after all, rather than 'hanning{num}.pdf'.format_map(my_dict), we could just as easily write 'hanning{num}.pdf'.format(**my_dict). However, this is useful for mappings that determine values on the fly, rather than ordinary dicts. In these cases, unpacking with ** might not work, because the set of keys might not be determined ahead of time; and trying to unpack keys based on the template is unwieldy (imagine: 'hanning{num}.pdf'.format(num=my_mapping[num]), with a separate argument for each placeholder).
string.Formatter
The string standard library module contains a rarely used Formatter class. Using it looks like string.Formatter().format('hanning{num}.pdf', num=num). The template string uses the same syntax again. This is obviously clunkier than just calling .format on the string; the motivation is to allow users to subclass Formatter to define a different syntax for the template string.
All of the above approaches use a common "formatting language" (although string.Formatter allows changing it); there are many other things that can be put inside the {}. Explaining how it works is beyond the scope of this answer; please consult the documentation. Do keep in mind that literal { and } characters need to be escaped by doubling them up. The syntax is presumably inspired by C#.
The % operator
This is a legacy way to solve the problem, inspired by C and C++. It has been discouraged for a long time, but is still supported. It looks like 'hanning%s.pdf' % num, for simple cases. As you'd expect, literal '%' symbols in the template need to be doubled up to escape them.
It has some issues:
It seems like the conversion specifier (the letter after the %) should match the type of whatever is being interpolated, but that's not actually the case. Instead, the value is converted to the specified type, and then to string from there. This isn't normally necessary; converting directly to string works most of the time, and converting to other types first doesn't help most of the rest of the time. So 's' is almost always used (unless you want the repr of the value, using 'r'). Despite that, the conversion specifier is a mandatory part of the syntax.
Tuples are handled specially: passing a tuple on the right-hand side is the way to provide multiple arguments. This is an ugly special case that's necessary because we aren't using function-call syntax. As a result, if you actually want to format a tuple into a single placeholder, it must be wrapped in a 1-tuple.
Other sequence types are not handled specially, and the different behaviour can be a gotcha.
string.Template
The string standard library module contains a rarely used Template class. Instances provide substitute and safe_substitute methods that work similarly to the built-in .format (safe_substitute will leave placeholders intact rather than raising an exception when the arguments don't match). This should also be considered a legacy approach to the problem.
It looks like string.Template('hanning$num.pdf').substitute(num=num), and is inspired by traditional Perl syntax. It's obviously clunkier than the .format approach, since a separate class has to be used before the method is available. Braces ({}) can be used optionally around the name of the variable, to avoid ambiguity. Similarly to the other methods, literal '$' in the template needs to be doubled up for escaping.
I had a need for an extended version of this: instead of embedding a single number in a string, I needed to generate a series of file names of the form 'file1.pdf', 'file2.pdf' etc. This is how it worked:
['file' + str(i) + '.pdf' for i in range(1,4)]
You can make dict and substitute variables in your string.
var = {"name": "Abdul Jalil", "age": 22}
temp_string = "My name is %(name)s. I am %(age)s years old." % var

Jinja2 template find and replace string with new format

I have a variable whose value is say FileSystem, I would like to get this printed as file_system in my template. Observe I am doing 2 things here:
1. If the first letter of my string is capital letter then I am converting it to lower
2. If any of my other letters is in caps, then I am replacing it with underscore followed by its lower string format.
One more example would be converting StackOverFlow to stack_over_flow
How can I get this done?
You could write a custom jinja filter that takes your variable as input and allows you to apply your desired transformation.
Quoted from the official jinja help:
Custom filters are just regular Python functions that take the left side of the filter as first argument and the arguments passed to the filter as extra arguments or keyword arguments.
jinja help section for custom filters
Example:
def convert_to_snakecase(value):
# convert your value here (lower case first letter + snake case)
return formatted_value
Register your custom filter:
app.jinja_env.filters['convert_to_snakecase'] = convert_to_snakecase
Call your filter inside the template:
{{ my_variable|convert_to_snakecase }}

In flask, Is it possible to use url convertor without splitting them using slash '/'?

I have a route:
#app.route("/login/<user>/<timestamp>")
def user(user, timestamp):.
But, I need it in this form -
#app.route("/login/<user><timestamp>")
def user(user, timestamp):.
i.e without the slash('/').
Is there any way to do it ?
Short answer: It is possible given the two parameters have a non-overlapping pattern. By giving it a wildcard-pattern however (you did not specify the converter). It will result in the fact that all content is handled to the user. That being said, it is advisable to have a clear separator.
As is specified in the documentation, you can define variables by writing them like HTML tags, like <var>, you can also specify a converter, like <converter:var>. If you do not specify a converter, the parameter is assumed to be a string that can not contain slashes.
There are however other converters, like int, float, path and uuid.
If the patterns are written in such way that it is clear when the first pattern ends, and the second pattern begins, then it this can be handled. For example:
#app.route("/login/<int:day><user>")
can work, given user can not start with a digit, since here once the sequence of digits ends, Flask will parse the <user> parameter.
By writing #app.route("/login/<user><timestamp>") however, the two patterns are overlapping: if we do not have a parsing strategy any split could be a valid one. Since the engine is greedy if I recall correctly, in practice it will result in the fact that user takes all characters, and timestamp none.
Since the default string does not include a slash, we know that the slash acts as a clear separator, since it is not included in both variables in your example.

Is it possible to declare a variable with a value for string and a placeholder in python?

I am trying to initialize a long string value to a variable, but this string has a word that can not be constant, like this example.
Say I want to store a string like this.
str = "https://stackoverflow.com/users/7833397/meskerem"
But assume the number 7833397 will change over time, so I am trying to find a way to store the string while making making a wildcard for the number. But I am not sure if this can be done in Python
Use the format method.
template = "https://stackoverflow.com/users/{0}/meskerem"
# Lots of stuff happens here
url = template.format("7833397")
The format method supports its own little mini language, and depending on your use-case you may find it more intuitive to name the various parts of your template, too:
template = "https://stackoverflow.com/users/{id}/{username}"
# Lots of stuff happens here
url = template.format(id="7833397", username="meskerem")
First, avoid usign the identifier str. Second, you can put placeholders in strings using two methods of string formatting:
Old style
The "old" style uses C-style string formatting syntax, and "modulo" operation on the string to do the actual insertion. You can pass multiple replacements as a tuple:
s = "foo%sbaz" # expects a string
print(s%"bar")
s2 = "foo%s%d"
print(s2%("bar", 2))
New style
The "new" style uses a generic {} which can be filled using the str.format() method. Multiple replacements are passed as a unzipped tuple, i.e. as mutiple arguments:
s = "foo{}baz" # can be "anything"
print(s.format("bar"))
s2 = "foo{}{}"
print(s2.format("bar", 2))
This site might come handy as a reference.
You can use '%s'(string formatting syntax )
modified_str = "https://stackoverflow.com/users/%s/meskerem" % (number,)

Getting two strings in variable from URL in Django

I'm having some trouble sending along more than one variable to the view.
my urls.py is as follows:
urlpatterns = patterns('',
url(r'^rss/(?P<anything>[^/]+)/$', 'rss.rssama.views.makerss', name='anything'),
url(r'^$', 'rss.rssama.views.home'),
)
views.py
def maakrss(request, anything):
So now it takes from www.mydomain.com/rss/[anything]/ and sends 'anything' to my view. However I also want it to send along another string to views.py, like:
www.mydomain.com/rss/[anynumber]/[anystring]/
I tried this but that didn't work:
url(r'^rss/(?P<anynumber>[^/]+)/(?P<anystring>[^/]+)/$', 'rss.rssama.views.makerss', name='anynumber', name2='anystring'),
But this doesn't work, it gives this error: keyword argument repeated (urls.py, line 17)
So my question: How can I make it to give along two string from the url?
To begin with, the regex part should look like this:
r'^/rss/(?P<anynumber>\d+)/(?P<anystring>.+)/$'
Those strings inside the <...> parts allow you to give a name to whatever the regex matches. Django will then use that name to pass the value to your function. Therefore your function must have an argument with the same name. In this case, Django will take the value called anynumber and use that value for the parameter of your function that is called anynumber. The same goes for anystring, and this system frees you from worrying about what order the arguments of your function are in.
\d+ will match one or more numeric characters (digits). It's good practice to limit the regex to match only numbers if that's what you intend to catch, rather than any character and hope that only numbers appear. If you wanted to limit the digits part to a certain number of digits, you could use \d{1,4} to take from one to four digits.
The next part, (?P<anystring>.+) will catch a string consisting of one or more of any characters. This would actually match something like 'letters/moreletters', including the slash. There are a number of "special sequences" in Python regex that might help. To match only digits, letters, and the underscore character, use \w, as in (?P<anystring>\w+). To be more lax but ignore whitespace or any other non-sense, (?P<anystring>[a-zA-Z1-9:;_{}\[\]] to catch a whole slew of characters. Make sure to escape anything that might be a special character in a regex. However, be conservative. If you allow too many options who knows what sorts of bugs you'll have to work out later.
Now onto name parameter of the url function. That name is not what it will pass the caught patterns to your functions as. It's a name for a particular class of invocation of your view function that can be used as a short-hand in other contexts like, the template tag {% url view-name arg1 arg2 %}. So, the name you have already, "anything", refers to a call to your view function, passing it one keyword argument that happens to be called anything. For the case where you want to pass two strings, give that a name like "rss-number-string" to signify the arguments you want to take, or a name that refers to the special function your view will be performing with that combination.
I use multiple names for the same function all the time, and the key is this:
def makerss(request, anystring=None, anynumber=None):
By giving the parameters default values, it allows you to use the same function in different ways. In this case, the function can be used when you only want to pass a value for anystring, or when anystring and anynumber should have values.
I know this is a lot of different points, so I'll try to put it all together so you can see how it might work. To have two urls, one which catch a string and passes it on, and another which catches a number, a slash, and then a string, but both point to the same view function, you could use this:
urlpatterns = patterns('',
url(r'^rss/(?P<anystring>\w+)/$', 'rss.rssama.views.makerss', name='rss-anystring'),
url(r'^rss/(?P<anynumber>\d+)/(?P<anystring>\w+)/$', 'rss.rssama.views.makerss', name='rss-number-string'),
url(r'^$', 'rss.rssama.views.home'),
)
With a view function something like this:
def makerss(request, anystring=None, anynumber=None):
if anystring:
if anynumber:
#Do something with the string and the number
else:
#Do something with just the string
Please let me know if this helps. Also, Django rocks, so kudos!
Python Regex Library Docs
You don't really need to give two name arguments for this. I mean, you already have the variable names inside regex. The actual problem is, you cannot give two name arguments, so you can do this instead:
url(r'^rss/(?P<anynumber>[^/]+)/(?P<anystring>[^/]+)/$', 'rss.rssama.views.makerss',name='something'),
EDIT:
using the urlConf above you can create corresponding view as:
def makerss(request, anynumber, anystring):
What is name2 supposed to be? The url function takes a name parameter, which is the name of the URL when you reverse it, but you can't put random extra functions.
Otherwise, you have the right syntax for sending two elements to a view. Of course, since you've masked the variable names and not provided the actual error or traceback, we have no way of knowing what really is going wrong.

Categories