django项目的urls.py与views.py之间的关联

2 投票
2 回答
557 浏览
提问于 2025-04-18 06:11
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),
)

在这个代码示例中,我们有两个文件:views.py 和 urls.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 文件中,提到的参数 offset 从匹配的 URL 中提取出来时,名字并不重要,位置才是关键。也就是说,offset 这个参数必须在 request 之后的位置,这样它才能正常工作。

那么,为什么会这样呢?hours_ahead 只是一个用户自己定义的方法,并不是一个类或者其他什么东西。是谁让这个参数的位置变得如此重要的呢?

所以,我想问的是,“offset = int(offset)” 这句代码有什么意义?为什么当用户设置小时数时,offset 能够从 URL 中接收到值呢?

2 个回答

1

Django的工作原理是这样的:它会读取这个网址模式 r'^time/plus/(\d{1,2})/$',然后提取出括号里面的参数(在这个例子中就是 (\d{1,2})),接着把这个参数作为一个输入传递给 hours_ahead 函数。如果网址模式里有多个参数,它们的顺序也会决定传递给对应的视图函数时的顺序。想了解更多,可以查看这里的文档:https://docs.djangoproject.com/en/dev/topics/http/urls/

0

这里说到的参数 offset 是从匹配的 URL 中提取的,名字不重要,但位置很关键。它是紧跟在 request 后面的第二个参数,决定了它能做什么。可是,为什么会这样呢?

在 Python 中,你可以给一个方法传递两种类型的参数:位置参数和关键字参数。位置参数是根据方法定义中的位置来决定的,顺序很重要(所以叫位置参数,因为它们在方法定义中的位置很重要)。

位置参数必须始终有值,它们是必填的。

关键字参数可以以任何顺序传递,只要它们是在位置参数之后传递的。关键字参数可以是可选的。

下面是一个例子:

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

ab 是位置参数,是必填的。你必须给它们传值。cd 是可选的关键字参数,有默认值。

第一个传入的参数会被称为 a,第二个是 b。之后,你可以传 dc 或者什么都不传:

>>> 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')

在 Django 的 urls.py 中,有两种方式来捕获 URL 的元素:

^time/plus/(\d+{1,2})/$ - 这个是捕获参数并作为位置参数传递。正则表达式捕获的结果会被传递给映射的请求函数的第二个参数,不管这个参数叫什么(第一个参数通常叫 request)。

为了映射上面的 URL,你必须有一个视图方法,接受 恰好两个位置参数,但它们可以随便命名。记住,request 是第一个位置参数。考虑一下这个:

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})/$ - 这种语法(叫做 命名组)将正则表达式的结果作为 关键字参数 传递给映射的 URL 函数。这意味着,两个数字的值会作为关键字参数 offset 传递给视图函数。你可以在 Django 文档 中了解更多关于命名组的信息。

如果你有上述命名组的 URL 模式,那么你的请求方法应该有以下签名:

def hours_ahead(request, offset)

作为一个例子,考虑这个 URL 模式:

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

要匹配这个模式,你的视图函数必须有以下签名:

def foo(request, a, b, hello)

当你接收到以下 URL time/32/42/world/ 时,a 的值会是 32,b 的值会是 42,而 hello 的值会是 world。

如果你在视图方法中把 hello 改成其他的,比如 def foo(request, a, b, blah),你的 URL 就无法映射,因为这个模式特别在寻找函数签名中的 关键字 hello

撰写回答