Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

url_for creates a url query string with &

Lets say i have the following script in a html template of a flask application

<script type="text/javascript">
  console.log('{{ url_for('root', arg1='hello', arg2='world') }}')
<script>

and i have a flask endpoint root()

@app.route('/', methods=['GET'])
def root():
  print(print(request.args))

when i call my page the internal script is rendered to

console.log('/api/art_structure?arg2=world&amp;arg1=hello')

When I call this url my request.args dict is:

ImmutableMultiDict([('amp;arg1', 'hello'), ('arg2', 'world')])

Which is not correct since the key of arg1 is wrong. Any clues how I can prevent jinja2 from converting & to &amp;?

like image 814
jan-seins Avatar asked Dec 13 '22 15:12

jan-seins


1 Answers

The ampersand

The correct URL is /api/art_structure?arg2=world&arg1=hello.

The problem with the above URL is that ampersand (&) cannot be written directly in HTML, because the ampersand is used for entity references. For example, to write < character in HTML, which is not a tag start, one can write &lt;. Because of that, to write &, one should escape it, i.e. write it as &amp;.

Jinja2 templating engine does that by default. So, you can dump the contents of any string variable even if it contains special characters and they will be correctly escaped, e.g. & will become &amp; as in your case.

How does that work?

So, if you actually put this in your jinja template: <a href="{{ url_for('root', arg1='hello', arg2='world') }}">link</a>, it would write the following HTML code: <a href="/api/art_structure?arg2=world&amp;arg1=hello">link</a>, and if you clicked on the link in the browser, it would correctly replace &amp; with & and open /api/art_structure?arg2=world&arg1=hello.

(note, however, that writing plain & as it is into HTML may sometimes also work, because browsers may guess how to fix the error)

So why does it not simply work in this case?

Because you are generating JavaScript and not HTML (you are generating code within <script> and </script>. In JavaScript, & is fine and should not be escaped, so you are free to write it as it is. To tell Jinja that you do not want it to escape the string, you can use the safe filter, i.e. {{ url_for('root', arg1='hello', arg2='world') | safe}}.

like image 105
zvone Avatar answered Dec 31 '22 23:12

zvone