Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting two strings in variable from URL in Django

Tags:

python

url

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?

like image 651
Javaaaa Avatar asked May 28 '11 21:05

Javaaaa


2 Answers

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

like image 176
Kevin Ward Avatar answered Sep 25 '22 02:09

Kevin Ward


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):
like image 43
Hgeg Avatar answered Sep 26 '22 02:09

Hgeg