Question

views.py

from django.http import Http404, HttpResponse import datetime

def hours_ahead(request, offset): 
    try:
        offset = int(offset) 
    except ValueError:
        raise Http404()
    dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
    html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)        
    return HttpResponse(html)

urls.py

from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime, hours_ahead

urlpatterns = patterns('',
    (r'^hello/$', hello),
    (r'^time/$', current_datetime), 
    (r'^time/plus/(\d{1,2})/$', hours_ahead),
)

it says the parameter offset which value extract from the matching url care nothing about its name,but position matters. It's its second parameter standing after request that decide what it can do. But why ? hours_ahead , is just a user-defined method, not a class or something. Who give its power that make the parameter's position can work that way. So be clear, my question is , "offset = int (offset)" does it make any sense, why can offset receive the value from url when user set the hours's.

Was it helpful?

Solution 2

it says the parameter offset which value extract from the matching url care nothing about its name,but position matters. It's its second parameter standing after request that decide what it can do. But why ?

In Python, there are two kinds of arguments you can pass to a method. Positional arguments and keyword arguments. Positional arguments are based on the position in the method's signature, and their order is important (that's why they are called positional, because their position in the method's signature is important).

Positional arguments must always have a value. They are not optional.

Keyword arguments are those that can be passed in any order - as long as they are passed in after positional arguments. Keywords arguments may be optional.

Here is an example:

def foo(a, b, c='Hello', d='World'):
    print(a,b,c,d)

a and b are positional arguments. They are required. You must pass in a value. c and d are optional keyword arguments, with their default values.

The first argument passed will be referred to by a, the second b. After that, you can pass either d, or c or none:

>>> foo(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes at least 2 arguments (1 given)
>>> foo(1,2)
(1, 2, 'Hello', 'World')
>>> foo(1,2,d='Yes')
(1, 2, 'Hello', 'Yes')
>>> foo(1,2,d='Yes',c='No')
(1, 2, 'No', 'Yes')

Now, in django's urls.py - there are two ways to capture elements of the URL:

^time/plus/(\d+{1,2})/$ - this is capturing the argument and passing it as a positional argument. The result of the regular expression captured will be passed to the second argument to the mapped request function, whatever that argument is called (the first argument is typically called request).

To map the above url, you must have a view method that takes exactly two positional arguments, but they can be called whatever you like. Remember, request is the first positional argument. Now with that in mind, consider this:

def foo(request, a) # You must have two positional arguments
def foo(request, b) # It does not matter what the second argument is called
def foo(request, a, b='world') # You can have any number of
                               # additional keyword arguments
                               # but they must be optional (have defaults)

def foo(request, a, b, c='world') # This will fail because you have two
                                  # positional arguments, but only one pattern is
                                  # captured in the URL.

^time/plus/(?P<offset>\d+{1,2})/$ - This syntax (called a named group) passes the result of the regular expression as a keyword argument to the mapped URL function. This means, that the value of the 2 digits will passed as the keyword argument offset to the view function. You can read more about named groups in URLs at the django documentation.

If you have the above named group URL pattern, then your request method should have the following signature:

def hours_ahead(request, offset)

As an example, consider this URL pattern:

^time/(\d+{1,2})/(\d+{1,2})/(?P<hello>\w+)/$

To match this pattern, your view function must have the following signature:

def foo(request, a, b, hello)

When you receive the following URL time/32/42/world/, a will be 32, b will be 42, and hello will have the value world.

If you change hello in your view method to something else, like def foo(request, a, b, blah) your URL will not get mapped because the pattern is specifically looking for the keyword hello in the function signature.

OTHER TIPS

The way it works is that Django reads this url pattern r'^time/plus/(\d{1,2})/$', extracts the parameters that are enclosed in parenthesis (which is (\d{1,2}) in this case), then passes it as argument to the hours_ahead function. If there are many parameters, the order at which they are written in the url pattern also dictates the order that they are passed into the corresponding view function. You can read further on the docs here: https://docs.djangoproject.com/en/dev/topics/http/urls/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top