67

I started using Django release 1.5 and got a problem with my old code:

<a href="{% url auto.views.viewpost post.slug %}"><h3>{{post.title}}</h3></a>

Error: 'url' requires a non-empty first argument. The syntax changed in Django 1.5, see the docs. Docs:

One deprecated feature worth noting is the shift to “new-style” url tag. Prior to Django 1.3, syntax like {% url myview %} was interpreted incorrectly (Django considered "myview" to be a literal name of a view, not a template variable named myview). Django 1.3 and above introduced the {% load url from future %} syntax to bring in the corrected behavior where myview was seen as a variable.

The upshot of this is that if you are not using {% load url from future %} in your templates, you’ll need to change tags like {% url myview %} to {% url "myview" %}. If you were using {% load url from future %} you can simply remove that line under Django 1.5

Then I tried: <a href=“{% url ‘auto.views.view_post’ post.slug %}”><h3>{{post.title}}</h3></a> but got error Reverse for ‘auto.views.view_post’ with arguments ‘(’',)' and keyword arguments ‘{}’ not found. :( What am I doing wrong? Thx!

Wolter
  • 1,053
  • 3
  • 11
  • 17
  • Is `auto` on Django's `PYTHONPATH`? Maybe you need something like `'somedir.auto.views.view_post'` there? And a more obvious question, is `auto.views.view_post` mentioned in your URLconf? – Lev Levitsky Feb 14 '13 at 19:29

6 Answers6

89

I really hate doing all this junk by hand, so I wrote a sed script to do it for me. Make sure you have a backup first, then run this in your templates directory:

find . -type f -print0 | xargs -0 sed -i 's/{% url \([^" >][^ >]*\)/{% url "\1"/g'

It'll go through all of your template files and replace this:

{% url something.else foo bar %}

with this

{% url "something.else" foo bar %}

Be careful, I was a little lazy with this, it might break on some constructs. It's still going to be easier looking for errors in a diff than doing it by hand, though.

olau
  • 93
  • 1
  • 6
Stephen Fuhry
  • 12,624
  • 6
  • 56
  • 55
  • 7
    For people using an editor (ultraedit etc) to fix this. This unix regex did the job for me: Find: ({% url+ )([0-9a-z_]+) Replace With: \1'\2' – Thomas Kremmel Mar 28 '13 at 15:04
  • 7
    for mac users: `find . -type f -print0 | xargs -0 sed -i.bak -e 's/ url \([^" >][^ >]*\)/ url "\1"/g'` this will create a backup file for every replace – Hassek May 14 '13 at 22:55
  • git branch fix_urls; git checkout fix_urls; find . -type f -print0 | xargs -0 sed -i 's/ url \([^" >][^ >]*\)/ url "\1"/g'; git gui / then test and merge. Took some minutes to run on my project. So don't freak out if your waiting for 5 minutes – Nathan Keller May 15 '13 at 00:38
  • 7
    PyCharm: Search for `(\{% *url +)([0-9a-z_.]+)` and replace with `{%url "$2"` (or `$1 "$2"` to preserve spaces) – Tom Leys Oct 16 '13 at 01:41
  • On osx add empty backup extension after ``-i``, so syntax becomes: ``find . -type f -print0 | xargs -0 sed -i '' 's/ url \([^" >][^ >]*\)/ url "\1"/g'``. See http://stackoverflow.com/questions/7573368/in-place-edits-with-sed-on-os-x – bmihelac Nov 12 '13 at 17:18
  • 3
    Here's a PyCharm regex that worked better for me: Search for `(\{% *url +)([0-9a-z\-_.]+)` and replace with `$1"$2"` -- it handles URL names containing hyphens, and preserves whitespace. – gldnspud May 22 '14 at 18:50
  • The PyCharm regex above by @gldnspud should actually be `(\{% *url +)([0-9a-z\-_\.]+)`. I escaped the dot at the end of the second pattern. – jumand May 26 '15 at 21:06
4

To exclude folder of .git and to avoid error's MacOS added empty quotes to option -i ''. Example:

find . -path '*/.git*' -prune -o -type f -print0 | xargs -0 sed -i '' 's/ url \([^" >][^ >]*\)/ url "\1"/g'

But I like this approach (MacOS):

grep '{% url' -lrZ . | xargs -0 sed -i '' 's/ url \([^" >][^ >]*\)/ url "\1"/g'
Abbasov Alexander
  • 1,848
  • 1
  • 18
  • 27
3

Firstly, you were correct to use single quotes for the view name, i.e. 'auto.views.view_post'.

Now, temporarily remove the url tag, and check that {{ post }} and {{ post.slug }} give you the values you expect. The error message arguments '('',)' suggests that post.slug is the problem.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
0

If you are using Mac OS you'll need to pass -e

find . -type f -print0 | xargs -0 sed -i -e 's/ url \([^" >][^ >]*\)/ url "\1"/g'
mac2017
  • 445
  • 1
  • 6
  • 16
0

I was getting an "ILLEGAL BYTE SEQUENCE" error from sed with most of these recipes, which I was able to fix by doing this first:

LANG=C

However, these recipes generated tons of false positives on my project, and we already had a mix of url names that were single-quoted, double-quoted, or unquoted. It was a mess. Turned out the cleanest approach was to just search the templates directory with my editor (Sublime) in regex mode for:

\{\%\ url\ [^']
\{\%\ url\ [^"]

(find all instances that weren't already quoted) and go through them visually. That turned out to be faster and cleaner than trying to automate it and then clean up the mess afterwards.

shacker
  • 14,712
  • 8
  • 89
  • 89
0

you may also need to do regexp-replace "\{% url "([\w:]+)" for "\{% url '$1' in order to aviod syntax errors like <a href="{% url "foo:bar" %}">baz</a>

rioted
  • 1,076
  • 13
  • 24