第三章 视图和URL配置
view翻译成视图真的有必要么... 这一章里view就没管过什么跟ui有关的事情 都是整理需要输出的数据 把view翻译成视图 还不如干脆把url也翻译成网址算了
https://docs.djangoproject.com/en/1.6/intro/reusable-apps/#your-project-and-your-reusable-app
前一章中,我们解释了如何建立一个 Django 项目并启动 Django 开发服务器。 在这一章,你将会学到用Django创建动态网页的基本知识。
你的第一个基于Django的页面: Hello World
Hello world.
如果你曾经发布过Hello world页面,但是没有使用网页框架,只是简单的在hello.html文本文件中输入Hello World,然后上传到任意的一个网页服务器上。 注意,在这个过程中,你已经说明了两个关于这个网页的关键信息: 它包括(字符串 "Hello world")和它的URL( http://www.example.com/hello.html , 如果你把文件放在子目录,也可能是 http://www.example.com/files/hello.html)。
使用Django,你会用不同的方法来说明这两件事 页面的内容是靠view function(视图函数) 来产生,URL定义在 URLconf 中。首先,我们先写一个Hello World视图函数。
第一份视图:
在上一章使用django-admin.py startproject制作的mysite文件夹中,创建一个叫做views.py的空文件。这个Python模块将包含这一章的视图。 请留意,Django对于view.py的文件命名没有特别的要求,它不在乎这个文件叫什么。但是根据约定,把它命名成view.py是个好主意,这样有利于其他开发者读懂你的代码,正如你很容易的往下读懂本文。
好像在1.4.0版本以后的mysite目录中有两层文件夹:/mysite:【/mysite:【init.py,settings.py,urls.py,wsgi.py】manage.py】,这views.py的目录到底在哪没有交代清楚
强烈要求注明views.py必须要放在里面一层的mysite目录,跟urls.py同级。新版的是两层目录 mysite: manage.py mysite: views.py ...... 不然很容易让我们这些新手误会
一定要放到mysite/mysite 目录,因为只有后一级中含有__init__.py,import 引入的是后一级的模块,至于是view.py还是views.py无关紧要,只要和url中的import的引入py文件同名就可
一定要放到mysite/mysite 目录,因为只有后一级中含有__init__.py,import 引入的是后一级的模块,至于是view.py还是views.py无关紧要,只要和url中的import的引入py文件同名就可 当然也可以直接去掉mysite , from view import hello ,只因view.py在mysite/mysite 目录中
我们的Hello world视图非常简单。 这些是完整的函数和导入声明,你需要输入到views.py文件:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello world")
我们逐行逐句地分析一遍这段代码:
首先,我们从 django.http 模块导入(import) HttpResponse 类。参阅附录 H 了解更多关于 HttpRequest 和 HttpResponse 的细节。 我们需要导入这些类,因为我们会在后面用到。
接下来,我们定义一个叫做hello 的视图函数。
每个视图函数至少要有一个参数,通常被叫作request。 这是一个触发这个视图、包含当前Web请求信息的对象,是类django.http.HttpRequest的一个实例。在这个示例中,我们虽然不用request做任何事情,然而它仍必须是这个视图的第一个参数。
注意视图函数的名称并不重要;并不一定非得以某种特定的方式命名才能让 Django 识别它。 在这里我们把它命名为:hello,是因为这个名称清晰的显示了视图的用意。同样地,你可以用诸如:hello_wonderful_beautiful_world,这样难看的短句来给它命名。 在下一小节(Your First URLconf),将告诉你Django是如何找到这个函数的。
这个函数只有简单的一行代码: 它仅仅返回一个HttpResponse对象,这个对象包含了文本“Hello world”。
这里主要讲的是: 一个视图就是Python的一个函数。这个函数第一个参数的类型是HttpRequest;它返回一个HttpResponse实例。为了使一个Python的函数成为一个Django可识别的视图,它必须满足这两个条件。 (也有例外,但是我们稍后才会接触到。
你的第一个URLconf
现在,如果你再运行:python manage.py runserver,你还将看到Django的欢迎页面,而看不到我们刚才写的Hello world显示页面。 那是因为我们的mysite项目还对hello视图一无所知。我们需要通过一个详细描述的URL来显式的告诉它并且激活这个视图。 (继续我们刚才类似发布静态HTML文件的例子。现在我们已经创建了HTML文件,但还没有把它上传至服务器的目录。)为了绑定视图函数和URL,我们使用URLconf。
URLconf 就像是 Django 所支撑网站的目录。 它的本质是 URL 模式以及要为该 URL 模式调用的视图函数之间的映射表。 你就是以这种方式告诉 Django,对于这个 URL 调用这段代码,对于那个 URL 调用那段代码。 例如,当用户访问/foo/时,调用视图函数foo_view(),这个视图函数存在于Python模块文件view.py中。
前一章中执行 django-admin.py startproject 时,该脚本会自动为你建了一份 URLconf(即 urls.py 文件)。 默认的urls.py会像下面这个样子:
from django.conf.urls.defaults import *
# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()
urlpatterns = patterns('',
# Example:
# (r'^mysite/', include('mysite.foo.urls')),
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the next line to enable the admin:
# (r'^admin/', include(admin.site.urls)),
)
出现错误: AttributeError at /hello 'str' object has no attribute 'resolve' Request Method: GET Request URL: http://127.0.0.1:8000/hello Django Version: 1.5.1 Exception Type: AttributeError Exception Value: 'str' object has no attribute 'resolve' Exception Location: /usr/local/lib/python2.7/dist-packages/django/core/urlresolvers.py in resolve, line 321
1.7.1中urls.py导入了两个包,分别是from django.conf.urls import patterns,include,url from django.contrib import admin
django2.8 """mysite URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/1.8/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') Including another URLconf 1. Add an import: from blog import urls as blog_urls 2. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) """ from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^admin/', include(admin.site.urls)), ]
from django.conf.urls.defaults import * 这行代码在新版django已经用不了了,必须把default去掉。改为 from django.conf.urls import * 然后一切正常。
较高的版本为: from django.conf.urls import url,include from django.contrib import admin
默认的URLconf包含了一些被注释起来的Django中常用的功能,仅仅只需去掉这些注释就可以开启这些功能. 下面是URLconf中忽略被注释的行后的实际内容
from django.conf.urls.defaults import *
urlpatterns = patterns('',
)
Django 1.6.1 的 urls.py 的第一行为: from django.conf.urls import patterns, include, url
Django1.10中urlpatterns与之前有所不同,是以 urlpatterns=[ url(r'^admin/', include(admin.site.urls)), url(........), ] 的形式,也就是说这里应该修改为: urlpatterns = [ url('^hello/$', hello), ]
#最新 from django.contrib import admin from django.urls import path urlpatterns = [ path('admin/', admin.site.urls), ]
让我们逐行解释一下代码:
- 第一行导入django.conf.urls.defaults下的所有模块,它们是Django URLconf的基本构造。 这包含了一个patterns函数。
- 第二行调用
patterns()函数并将返回结果保存到urlpatterns变量。patterns函数当前只有一个参数—一个空的字符串。 (这个字符串可以被用来表示一个视图函数的通用前缀。具体我们将在第八章里面介绍。)
当前应该注意是 urlpatterns 变量, Django 期望能从 ROOT_URLCONF 模块中找到它。 该变量定义了 URL 以及用于处理这些 URL 的代码之间的映射关系。 默认情况下,URLconf 所有内容都被注释起来了——Django 应用程序还是白版一块。 (注:那是上一节中Django怎么知道显示欢迎页面的原因。 如果 URLconf 为空,Django 会认定你才创建好新项目,因此也就显示那种信息。
如果想在URLconf中加入URL和view,只需增加映射URL模式和view功能的Python tuple即可. 这里演示如何添加view中hello功能.
from django.conf.urls.defaults import *
from mysite.views import hello
urlpatterns = patterns('',
('^hello/$', hello),
)
More information: It seems that you have to keep at least 1 up level name space. For example, you can import mysite, and use 'views.hello', but you can't import mysite.views to use 'hello'. Of course, at anytime, you can use full name space like 'mysite.views.hello'.
Jesus! The original setting works: from mysite.views import hello ('^hello/$', hello),
如果No module named mysite.urls 检查一下自己的setting.py文件 其中有一行是 ROOT_URLCONF = 'mysite.urls' 如果你是驼峰命名法的爱好者请将这里的mysite修改为正确的模式 我不知道这个算不算一个BUG.
我的错误是:Exception Value:No module named views 于是我把 from mysite.views import hello 改成 from mysite.view import hello
1.3里这里可以使用一个url的function了,url的参数就就和这里的tuple对应的使用.在1.3里也是可以用这个方式的。 eg: url('^hello/$',hello)
('^hello/$',hello) 或 ('^hello/$',“view.hello”) 用字符串的话,需要加上这个所在模块的名称哦 hello可以用一个字符串,也要以不加
此处的from mysite.views import hello 实际上应该是from views import hello 害我试了半天,我说怎么加载不了模块儿呢。靠。官网也是这么写的。
Using the URLconf defined in mysite.urls, Django tried these URL patterns, in this order: ^hello/$ The current URL, , didn't match any of these. How to solve this error?
django 1.4/python 2.7 import有错误,可改为(hello为函数对象) import views / views.hello 或者import views.hello / hello 修改源文件后,不需要重启server,重新编译代码,直接refresh网页即可。 设置APPEND_SLASH = False */hello url不能访问 ,/hello/
这段代码没有问题,在django1.4下运行也没有问题。若出错,请检查你所建的目录方式是不是和上文描述的一样;views.py你是不是写成了view.py;在浏览器地址栏中输入的地址是否为:127.0.0.1:8000/hello/
第二行 from mysite.views import hello 运行的时候一直提示没有views这个module,改成: from views import hello 保存后,访问http://127.0.0.1:8000/hello/ 能够成功显示hello word 视图。。
"from view import hello" works!According to the original writing, it warns "NO module names view"
('^hello/?$', hello),建议这里多个问号会更灵活,表示“/”允许出现0次或1次; 因为不是所有人都喜欢http://10.1.1.1:8000/hello/这样打开连接;有些人习惯http://10.1.1.1:8000/hello这样,后面不带“/”
1、URL 中的正確代碼是: from django.conf.urls import * from mysite.views import hello urlpatterns = patterns('', # Examples: # url(r'^$', 'mysite.views.home', name='home'), # url(r'^blog/', include('blog.urls')), ('^hello/$',hello), )
Mac Django 下正确的urls.py 内容为: from django.conf.urls import * from mysite.views import hello urlpatterns = patterns('', ('^hello/$','mysite.views.hello'),)
django 1.6 第一样需要:from django.conf.urls import patterns, include, url 才能成功,来回折腾验证了。
在django1.6中,按照例子写成: url(r'^hello/$', 'mysite.views.hello',name='hello')或者 url(r'^hello/$', 'mysite.views.hello')都可以
我的版本1.6。。看了下注释里的例子,教程里的这个现在前面要加url才能用,这个地方也可以这么写。。 可以去掉这句from mysite.views import hello 然后下面url('^hello/$,' 'mysite.views.hello') 或者可以上面的这么写from mysite import views 下面url('^hello/$', views.hello)
我是from mysite.view import hello可以运行 但是from view import hello 不等运行 可我不明白为什么 明明 view.py 和url.py 在同一个目录中啊
我是from mysite.view import hello可以运行 但是from view import hello 不等运行 可我不明白为什么 明明 view.py 和url.py 在同一个目录中啊 我明白了 目录是C:\web\mysite\mysite 而Python Path: ['C:\\web\\mysite',..] 也就是说它不能在当前目录里import 我用的是1.6
在django 1.5和1.6中view.py要和urls.py文件放在同一个目录下, urls.py中写 from 文件夹名.view import hello url(r'^hello/$' , hello), 或者直接写 url(r'^hello/$' , '文件夹名.view.hello' , name = 'hello'),d
xxs2010 2012-08-14 15:24:54 说的很对 这段代码没有问题,在django1.4下运行也没有问题。若出错,请检查你所建的目录方式是不是和上文描述的一样;views.py你是不是写成了view.py;在浏览器地址栏中输入的地址是否为:127.0.0.1:8000/hello/ 我就是没有在在浏览器地址栏的地址:127.0.0.1:8000后没有加/hello
我想说的是from mysite.views import hello#views.py 在books目录下,隶属于books的一个视图而不是在mysite目录下,这个一直跟着教程做下来的话from mysite.views import hello应该改成from books.views import hello,反正我是这么改一下就对了的看这里的意思应该是mysite目录下应该还有个叫做mysite的app子目录,教程在开始的时候命名就是books,所以我觉得这里应该是books
我使用python和django1.6.5发现按照文中描述的去写报No module named defaults Exception Location: ******mysite/mysite/urls.py in <module>, line 1Exception Location: /Users/ruanhongbo/Documents/python/Django_free/mysite/mysite/urls.py in <module>, line 1 然后去Django安装目录urls下查看果然发现无defaults文件,最后将导入包改为django.conf.urls.__init__ 便可成功。希望大家遇到此类问题都能解决。
python 2.7 + django 1.6.5 不要被patterns函数中自带的那个url(r'^admin/',include(admin.site.urls))影响,这里要写url(r'^Hello/', Hello)或者 (r'^Hello/', Hello)
python 2.7 + django 1.6.6 按照文中提示新建的 mysite 文件目录下还有一个 mysite 目录,先看看自己的 python 搜索路径有没有包含 mysite,没有的话还是乖乖的把 views.py 与 urls.py 放在同一个目录下。
高版本 1.6-1.7请修改为from views import hello, urlpatterns=patterns('',(r'^hello/$',hello))
这里确实是一个让人纠结的地方。 上面的有些方法也是可以用的,这是我自己参考注释改出来的urls.py下面的代码。直接127.0.0.1:8000下就直接显示helloworld。 代码 from django.conf.urls import patterns, include, url #from view import hello urlpatterns = patterns('', # Examples: # url(r'^$', 'mysite.views.home', name='home'), # url(r'^blog/', include('blog.urls')), #url(r'^admin/', include(admin.site.urls)), url(r'^$', 'mysite.view.hello', name='hello'), #(r'^hello/$', hello) )
这里确实是一个让人纠结的地方。 上面的有些方法也是可以用的,这是我自己参考注释改出来的urls.py下面的代码。直接127.0.0.1:8000下就直接显示helloworld。 代码 from django.conf.urls import patterns, include, url urlpatterns = patterns('', # Examples: # url(r'^$', 'mysite.views.home', name='home'), url(r'^$', 'mysite.view.hello', name='hello'), )
from django.conf.urls import patterns, include, url Django 1.7 把第一行改成这个就可以了
使用django1.8版本,urls.py中写成如下即可: from django.conf.urls import url, include urlpatterns = [ url(r'^$', 'mysite.views.hello'), ]
from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ # Examples: url(r'^$', 'mysite.views.hello', name='hello'), # url(r'^blog/', include('blog.urls')), url(r'^admin/', include(admin.site.urls)), ] django1.8亲测
一直不成功,看了这个手册里的例子:https://docs.djangoproject.com/en/1.8/topics/http/urls/ 第一个import 换成 from django.conf.urls import url即可,不知道为什么,还是官方手册好点吧
1.8.1 from django.conf.urls import include, url from django.contrib import admin import views urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^hello/$',views.hello) ] 成功运行
django-1.8.3 python-2.7.9 只改 urlpatterns = [ url('^hello/$', 'mysite.views.hello') ] 在“http://127.0.0.1:8000/hello/”下运行成功
从根本上来说,你的服务是从 mysite 文件下的manage开始的。也就是说mysite是根目录,Django的sys.path路径里面有包括当前目录,也就是~/mysite。所以from mysite.views import hello 查找的是~/mysite/mysite/views 如果你的views在这个目录下,就找得到。如果没有就报错。
@loguis 肯定不能用 mysite,比如说我的 project 名称是 temp ,那么 from temp.views import hello 和 import views 是一致的。具体参见 Python 的模块环节
Django1.6.8 test 图例版本太低 #################3 rom django.conf.urls import * from mysite.views import hello urlpatterns = patterns('', ('^hello/$', hello), )
Python3,Django1.8: 根据urls.py顶部给出注释,from mysite import views,url(r'^hello/', views.hello, name='hello'),亲测可用
最新的django 1.9.6版本,似乎要这样才行 from django.conf.urls import url from mysite.views import hello urlpatterns = [ url(r'^hello/', hello, name='hello'), ] 按照文件注释的说明来的
最新的django 1.10版本+py2.7下面可以实现 from django.conf.urls import * from mysite.views import hello urlpatterns = [ url(r'^hello/', hello, name='hello'), ]
If your django is 1.8.16 or higher, you should change this line:"from django.conf.urls.defaults import *" into "from django.conf.urls import *". Then notice the url:"http://127.0.0.1:8000/hello/", do not miss the "/" in the end.
python3.4,django 1.7.1 from mysite.mysite.views import hello才能识别hello模块,输入http://localhost:8080/hello/报错404
P27+D1.10,import view urlpatterns = [ url(r'^admin/', admin.site.urls),url(r'^hello/$',view.hello) ],地址别忘+hello/,完美显示。
django 1.10版本,需要改成如下: from django.conf.urls import * from views import hello urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^hello/', hello), ]
P27.13+D1.11,之前一直都是“patterns”“default”等等未定义,根据楼上的建议再导入admin,完美实现,亲测可用 from django.conf.urls import * from views import hello from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^hello/', hello), ]
还有就是,views.py我把它放到了和urls.py同一级目录里,不知道为什么mysite文件夹里又有一个mysite文件夹,而且manage.py和settings.py不在同一目录
2017年版本可能不一样,我按照此教程一直提示没有patterns这个model,之后修改如下:from django.conf.urls import include, url from mysite.views import hello urlpatterns = [ url(r'^hello/$', hello), ]就好用了~
注意django版本,10之后不支持这样写了 from mysite import views as hello urlpatterns = patterns('', ('^hello', hello.helloworld, name='helloworld'), )
2.0.1版的django的urls 用的是path('^hello/$',mysite.views.hello),这样是有问题的,404.需要改成url('^hello/$',mysite.views.hello),
from django.conf.urls import url from . import view urlpatterns = [ url(r'^$', view.hello), ]
django2.2 + python3.6环境 from django.contrib import admin from django.conf.urls import url from django.urls import path from mysite.views import hello urlpatterns = [ path('admin/', admin.site.urls), url('^hello/$', hello), ] 可以运行
高版本django不需要匹配正则 from django.urls import path from mysite.views import hello urlpatterns = [ path('hello/', hello), ]
请留意:为了简洁,我们移除了注释代码。 如果你喜欢的话,你可以保留那些行。)
我们做了两处修改。
- 首先,我们从模块 (在 Python 的 import 语法中,
mysite/views.py转译为mysite.views) 中引入了hello视图。 (这假设mysite/views.py在你的Python搜索路径上。关于搜索路径的解释,请参照下文。) - 接下来,我们为urlpatterns加上一行: (‘^hello/$’, hello), 这行被称作URLpattern,它是一个Python的元组。元组中第一个元素是模式匹配字符串(正则表达式);第二个元素是那个模式将使用的视图函数。
"我们从模块 (在 Python 的 import 语法中, mysite/views.py 转译为 mysite.views ) 中引入了 current_datetime 视图。" --> 我们从模块 views(在 Python 的 import 语法中, mysite/views.py 转译为 mysite.views ) 中引入了 hello 视图。
ls 这个元组中的两个元素可以不相同 这两个元素起着不同的作用 第一个 是url地址 是你要输入浏览器中的 第二个是视图函数中的 函数名称 之所以把他们两个写在一个元组中 是为了使url地址与视图函数一一对应 url地址可以随意命名 视图函数的名称也是随意的 所以这两个元素名称可同 可不同 ls仔细看书的话 这一点不难理解
简单来说,我们只是告诉 Django,所有指向 URL /hello/ 的请求都应由 hello 这个视图函数来处理。
Python 搜索路径
Python 搜索路径 就是使用 import 语句时,Python 所查找的系统目录清单。
举例来说,假定你将 Python 路径设置为 ['','/usr/lib/python2.4/site-packages','/home/username/djcode/'] 。如果执行代码 from foo import bar ,Python 将会首先在当前目录查找 foo.py 模块( Python 路径第一项的空字符串表示当前目录)。 如果文件不存在,Python将查找 /usr/lib/python2.4/site-packages/foo.py 文件。
如果你想看Python搜索路径的值,运行Python交互解释器,然后输入:
>>> import sys
>>> print sys.path
通常,你不必关心 Python 搜索路径的设置。 Python 和 Django 会在后台自动帮你处理好。
讨论一下URLpattern的语法是值得的,因为它不是显而易见的。 虽然我们想匹配地址/hello/,但是模式看上去与这有点差别。 这就是为什么:
Django在检查URL模式前,移除每一个申请的URL开头的斜杠(/)。 这意味着我们为/hello/写URL模式不用包含斜杠(/)。(刚开始,这样可能看起来不直观,但这样的要求简化了许多工作,如URL模式内嵌,我们将在第八章谈及。)
模式包含了一个尖号(^)和一个美元符号($)。这些都是正则表达式符号,并且有特定的含义: 上箭头要求表达式对字符串的头部进行匹配,美元符号则要求表达式对字符串的尾部进行匹配。
最好还是用范例来说明一下这个概念。 如果我们用尾部不是$的模式’^hello/’,那么任何以/hello/开头的URL将会匹配,例如:/hello/foo 和/hello/bar,而不仅仅是/hello/。类似地,如果我们忽略了尖号(^),即’hello/$’,那么任何以hello/结尾的URL将会匹配,例如:/foo/bar/hello/。如果我们简单使用hello/,即没有^开头和$结尾,那么任何包含hello/的URL将会匹配,如:/foo/hello/bar。因此,我们使用这两个符号以确保只有/hello/匹配,不多也不少。
你大多数的URL模式会以^开始、以$结束,但是拥有复杂匹配的灵活性会更好。
你可能会问:如果有人申请访问/hello(尾部没有斜杠/)会怎样。 因为我们的URL模式要求尾部有一个斜杠(/),那个申请URL将不匹配。 然而,默认地,任何不匹配或尾部没有斜杠(/)的申请URL,将被重定向至尾部包含斜杠的相同字眼的URL。 (这是受配置文件setting中APPEND_SLASH项控制的,参见附件D。)
我所用的django版本是(1, 5, 4, 'final', 0),在默认生成的setting.py文件中,没有APPEND_SLASH项。 不过APPEND_SLASH = False项可以生效。
这个在global_settings.py里面有 global_settings.py在 C:\Python27\Lib...\django\conf\目录下面
linux底下,全局setting文件: /usr/local/lib/python2.7/site-packages/Django-1.7.1-py2.7.egg/django/conf/global_settings.py
使用的是django 1.1.3,windowsXp,globla_settings.APPEND_SLASH = False, URLconf ("^hello/$",hello),访问的是 xxx/hello, 为甚么也成自动匹配匹配上?(不是globla_settings.APPEND_SLASH = False不能匹配了么)
Python3,Django1.8: settings.py文件中没有 APPEND_SLASH 这一项,但是添加 APPEND_SLASH = False 后,访问 URL/hello 最后没有斜杠,会找不到网页,也就是说 APPEND_SLASH 项生效
win10里面,conda环境,在**/envs/condaName/Lib\site-packages\django\conf\global_settings.py中,可以看到APPEND_SLASH=True
如果你是喜欢所有URL都以’/’结尾的人(Django开发者的偏爱),那么你只需要在每个URL后添加斜杠,并且设置”APPEND_SLASH”为”True”. 如果不喜欢URL以斜杠结尾或者根据每个URL来决定,那么需要设置”APPEND_SLASH”为”False”,并且根据你自己的意愿来添加结尾斜杠/在URL模式后.
django1.2.3,在我的mysite目录下 settings.py没有 APPEND_SLASH呢? 但我在settings.py末尾添加APPEND_SLASH='False',在URL结尾依然会自动添加上“/”。求解。谢谢
django1.2.4,mysite目录下 settings.py没有 APPEND_SLASH,在settings.py末尾添加APPEND_SLASH=False,在URL结尾不会自动添加上"/"。设置为True,会自动加上"/"
看下django1.4.1对他的解释,我就不翻译了。 地址:https://docs.djangoproject.com/en/dev/ref/settings/ APPEND_SLASH Default: True When set to True, if the request URL does not match any of the patterns in the URLconf and it doesn't end in a slash, an HTTP redirect is issued to the same URL with a slash appended. Note that the redirect may cause any data submitted in a POST request to be lost. The APPEND_SLASH setting is only used if CommonMiddleware is installed (see Middleware). See also PREPEND_WWW.
在settings.py的最后加入APPEND_SLASH=‘False'(带带引号)或者APPEND = False(带空格),hello后面依然会自动添加上/,而加入APPEND_SLASH=False(紧贴),hello后面不会带上/,输入http://127.0.0.1:8000/hello,显示Page not found. 这是Python语法问题?
在settings.py的最后加入APPEND_SLASH=‘False'(带单引号)或者APPEND = False(带空格),hello后面依然会自动添加上/,而加入APPEND_SLASH=False(紧贴),hello后面不会带上/,输入http://127.0.0.1:8000/hello,显示Page not found. 这是Python语法问题?
ls,设置APPEND_SLASH = 'False',这种格式是字符串的形式,字符串非空即为True。至于第二种方式格式错误,使用默认值依然为True。
另外需要注意的是,我们把hello视图函数作为一个对象传递,而不是调用它。 这是 Python (及其它动态语言的) 的一个重要特性: 函数是一级对象(first-class objects), 也就是说你可以像传递其它变量一样传递它们。 很酷吧?
启动Django开发服务器来测试修改好的 URLconf, 运行命令行 python manage.py runserver 。 (如果你让它一直运行也可以,开发服务器会自动监测代码改动并自动重新载入,所以不需要手工重启) 开发服务器的地址是 http://127.0.0.1:8000/ ,打开你的浏览器访问 http://127.0.0.1:8000/hello/ 。 你就可以看到输出结果了。 开发服务器将自动检测Python代码的更改来做必要的重新加载, 所以你不需要重启Server在代码更改之后。服务器运行地址[http://127.0.0.1:8000](http://127.0.0.1:8000)/ ,所以打开浏览器直接输入[http://127.0.0.1:8000/hello](http://127.0.0.1:8000/hello)/ ,你将看到由你的Django视图输出的Hello world。
服务器运行地址`` http://127.0.0.1:8000/`` ,所以打开浏览器直接输入`` http://127.0.0.1:8000/hello/`` ,你将看到由你的Django视图输出的Hello world。--> 服务器运行地址“ http://127.0.0.1:8000/” ,所以打开浏览器直接输入“ http://127.0.0.1:8000/hello/”,你将看到由你的Django视图输出的Hello world。
不能出现HELLO WORLD 的原因之一,或许你是用pycharm 建立的Django 项目,你没把url(r'^admin/doc/', include('django.contrib.admindocs.urls')), 和url(r'^admin/', include(admin.site.urls))注释掉,所以会一直在欢迎界面,不能找到view,得到一个错误:Put 'django.contrib.admin' in your INSTALLED_APPS setting in order to use the admin application.
开发服务器的地址是 http://127.0.0.1:8000/ ,打开你的浏览器访问 http://127.0.0.1:8000/hello/ 。 你就可以看到输出结果了。 开发服务器将自动检测Python代码的更改来做必要的重新加载, 所以你不需要重启Server在代码更改之后。服务器运行地址`` http://127.0.0.1:8000/`` ,所以打开浏览器直接输入`` http://127.0.0.1:8000/hello/`` ,你将看到由你的Django视图输出的Hello world。 这两句话不是翻译重复了吧,好像是说的一个意思。
当输入http://127.0.0.1:8000/不会显示hello world在浏览器中,然而输入http://127.0.0.1:8000/hello/会显示。本人之前用pycharm创建的project。求大神解释说明一下原因。
URLconf里写的是('^hello/$', hello),就是访问http://.../hello/,才会跳到hello视图显示hello world。其他url都没有定义,所以你是正常的。
万岁! 你已经创建了第一个Django的web页面。
为什么会提示importerror呢,信息如下Exception Type: ImportError Exception Value: No module named views 明明hello函数就在view.py里啊,去掉了views的s还是不行。求解~
views.py 必须放到mysite/mysite目录下,否则会出错,no module named views 我也是一直找不到原因,自己无意间尝试成功的,原谅我小白。
正则表达式
正则表达式 (或 regexes ) 是通用的文本模式匹配的方法。 Django URLconfs 允许你 使用任意的正则表达式来做强有力的URL映射,不过通常你实际上可能只需要使用很少的一 部分功能。 这里是一些基本的语法。
关于“404错误”的快速参考
目前,我们的URLconf只定义了一个单独的URL模式: 处理URL /hello/ 。 当请求其他URL会怎么样呢?
让我们试试看,运行Django开发服务器并访问类似 http://127.0.0.1:8000/goodbye/ 或者 http://127.0.0.1:8000/hello/subdirectory/ ,甚至 http://127.0.0.1:8000/ (网站根目录)。 你将会看到一个 “Page not found” 页面(图 3-2)。 因为你的URL申请在URLconf中没有定义,所以Django显示这条信息。
图3-1: Django的404 Error页
这个页面比原始的404错误信息更加实用。 它同时精确的告诉你Django调用哪个URLconf及其包含的每个模式。 这样,你应该能了解到为什么这个请求会抛出404错误。
当然,这些敏感的信息应该只呈现给你-开发者。 如果是部署到了因特网上的站点就不应该暴露 这些信息。 出于这个考虑,这个“Page not found”页面只会在 调试模式(debug mode) 下 显示。 我们将在以后说明怎么关闭调试模式。
在最后一节,如果你想通过http://127.0.0.1:8000/看网站根目录你将看到一个404错误消息。Django不会增加任何东西在网站根目录,在任何情况下这个URL都不是特殊的 就像在URLconf中的其他条目一样,它也依赖于指定给它的URL模式.
尽管匹配网站根目录的URL模式不能想象,但是还是值得提一下的. 当为网站根目录实现一个视图,你需要使用URL模式‘^$’ , 它代表一个空字符串。 例如:
说一下修改的地方,比如默认用index方法,urls.py///from books.views import index//url(r'^$', index),////views.py///def index(request): return HttpResponse("Hello World-index")
from mysite.views import hello, my_homepage_view
urlpatterns = patterns('',
('^$', my_homepage_view),
# ...
)
Django是怎么处理请求的
在继续我们的第二个视图功能之前,让我们暂停一下去了解更多一些有关Django是怎么工作的知识. 具体地说,当你通过在浏览器里敲http://127.0.0.1:8000/hello/来访问Hello world消息得时候,Django在后台有些什么动作呢?
所有均开始于setting文件。当你运行python manage.py runserver,脚本将在于manage.py同一个目录下查找名为setting.py的文件。这个文件包含了所有有关这个Django项目的配置信息,均大写: TEMPLATE_DIRS , DATABASE_NAME , 等. 最重要的设置时ROOT_URLCONF,它将作为URLconf告诉Django在这个站点中那些Python的模块将被用到
脚本将在于manage.py同一个目录下查找名为setting.py的文件。改译为:脚本将在与manage.py相同的目录中查找名为setting.py的文件。
Python 2.7.3,Django verison 1.4.3中manage.py和settings.py不在同一个目录下,目录结构如下: mysite\ manage.py mysite\ _init_.py settings.py urls.py wsgi.py
Python 2.7.3,Django verison 1.4.3中manage.py和settings.py不在同一个目录下,目录结构如下: mysite\ ┗manage.py ┗mysite\ ┗_init_.py ┗settings.py ┗urls.py ┗wsgi.py
还记得什么时候django-admin.py startproject创建文件settings.py和urls.py吗?自动创建的settings.py包含一个ROOT_URLCONF配置用来指向自动产生的urls.py. 打开文件settings.py你将看到如下:
ROOT_URLCONF = 'mysite.urls'
相对应的文件是mysite/urls.py
当访问 URL /hello/ 时,Django 根据 ROOT_URLCONF 的设置装载 URLconf 。 然后按顺序逐个匹配URLconf里的URLpatterns,直到找到一个匹配的。 当找到这个匹配 的URLpatterns就调用相关联的view函数,并把 HttpRequest 对象作为第一个参数。 (稍后再给出 HttpRequest 的更多信息) (我们将在后面看到HttpRequest的标准)
正如我们在第一个视图例子里面看到的,一个视图功能必须返回一个HttpResponse。 一旦做完,Django将完成剩余的转换Python的对象到一个合适的带有HTTP头和body的Web Response,(例如,网页内容)。
“Django转换HttpResponse为一个适合的HTTP response, 以Web page显示出来” 后一个response应该翻译成中文:HTTP响应
总结一下:
- 进来的请求转入/hello/.
- Django通过在ROOT_URLCONF配置来决定根URLconf.
- Django在URLconf中的所有URL模式中,查找第一个匹配/hello/的条目。
- 如果找到匹配,将调用相应的视图函数
- 视图函数返回一个HttpResponse
- Django转换HttpResponse为一个适合的HTTP response, 以Web page显示出来
你现在知道了怎么做一个 Django-powered 页面了,真的很简单,只需要写视图函数并用 URLconfs把它们和URLs对应起来。 你可能会认为用一系列正则表达式将URLs映射到函数也许会比较慢,但事实却会让你惊讶。
第二个视图: 动态内容
我们的Hello world视图是用来演示基本的Django是如何工作的,但是它不是一个动态网页的例子,因为网页的内容一直是一样的. 每次去查看/hello/,你将会看到相同的内容,它类似一个静态HTML文件。
我们的第二个视图,将更多的放些动态的东西例如当前日期和时间显示在网页上 这将非常好,简单的下一步,因为它不引入了数据库或者任何用户的输入,仅仅是输出显示你的服务器的内部时钟. 它仅仅有限度的比Helloworld刺激一些,但是它将演示一些新的概念
这个视图需要做两件事情: 计算当前日期和时间,并返回包含这些值的HttpResponse 如果你对python很有经验,那肯定知道在python中需要利用datetime模块去计算时间 下面演示如何去使用它:
>>> import datetime
>>> now = datetime.datetime.now()
>>> now
datetime.datetime(2008, 12, 13, 14, 9, 39, 2731)
>>> print now
2008-12-13 14:09:39.002731
Old Syntax: print x New syntax: print (x, end="") #appends a space instead of a newline
以上代码很简单,并没有涉及Django。 它仅仅是Python代码。 需要强调的是,你应该意识到哪些是纯Python代码,哪些是Django特性代码。 (见上) 因为你学习了Django,希望你能将Django的知识应用在那些不一定需要使用Django的项目上。
the code here can be html=("<html> <body>It is now %s </body></html>"% now) or it can be a error result
为了让Django视图显示当前日期和时间,我们仅需要把语句:datetime.datetime.now()放入视图函数,然后返回一个HttpResponse对象即可。代码如下:
from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
正如我们的hello函数一样,这个函数也保存在view.py中。为了简洁,上面我们隐藏了hello函数。下面是完整的view.py文件内容:
只要记住和你import的名字保持一致就行了,不用计较是到底是view还是views,例如你的文件名为view,就是import <prjname>.view
我想问一下,既然django基于MVC模式,是不是就是指view.py属于view,urls.py属于controllwe。然后哪个文件属于model呢?setting.py和manage.py?
按照教程中这么写 def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html) 会在 html = "<html><body>It is now %s.</body></html>" % now 一行报IndentationError错误,检查了一下缩进没发现问题,把now一行改成now=1234(后来发现好像凡是带括号的就有问题),这是什么原因啊?
from django.http import HttpResponse
import datetime
def hello(request):
return HttpResponse("Hello world")
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
事实上,%s是比较差的python风格,最好的做法是 'Today is {day}, {month}'.format(day=today_day, month=today_month)
(从现在开始,如非必要,本文不再重复列出先前的代码。 你应该懂得识别哪些是新代码,哪些是先前的。) (见上)
让我们分析一下改动后的views.py:
在文件顶端,我们添加了一条语句:import datetime。这样就可以计算日期了。
函数中的第一行代码计算当前日期和时间,并以 datetime.datetime 对象的形式保存为局部变量 now 。
并以datetime.datetime对象的形式保存为局部变量now 这句话的意思 datetime.datetime 是一个对象吗?然后使用now来保存
函数的第二行代码用 Python 的格式化字符串(format-string)功能构造了一段 HTML 响应。 字符串中的%s是占位符,字符串后面的百分号表示用它后面的变量now的值来代替%s。变量%s是一个datetime.datetime对象。它虽然不是一个字符串,但是%s(格式化字符串)会把它转换成字符串,如:2008-12-13 14:09:39.002731。这将导致HTML的输出字符串为:It is now 2008-12-13 14:09:39.002731。
(目前HTML是有错误的,但我们这样做是为了保持例子的简短。)
最后,正如我们刚才写的hello函数一样,视图返回一个HttpResponse对象,它包含生成的响应。
添加上述代码之后,还要在urls.py中添加URL模式,以告诉Django由哪一个URL来处理这个视图。 用/time/之类的字眼易于理解:
from django.conf.urls.defaults import *
from mysite.views import hello, current_datetime
urlpatterns = patterns('',
('^hello/$', hello),
('^time/$', current_datetime),
)
我的必须写成:urlpatterns = patterns('',('^hello/$', 'mysite.views.hello'),('^time/$','mysite.views.current_datetime'))才能操作成功。'mysite.views.current_datetime'表示第二个mysite文件夹下views文件中的current_datetime。
奇怪,不能import current_time.而且再次去掉这个更新后的代码又能运行了,可惜哪怕我改变了“hello world”成为别的字符串,网页显示的依然是hello world!删除浏览器记录,缓存也不行!
一开始我也是接着原来的views.py写的,不好使,后来重新建了一个工程,里面也包含hello那块,就好使了。。。但是我代码和之前不好使的那个工程师一模一样的啊,不知道怎么回事。。。有人明白么?
{#urls.py里面要有 from books.views import hello,current_datetime#要有模式匹配url(r'^hello/$', hello), url(r'^time/$', current_datetime),}{views.py里面要有对应的方法,原谅我喊他方法,我也不知道叫啥,def hello(request): return HttpResponse("Hello World") def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
django.conf.urls.defaults 已经不能导入了 替换为from django.conf.urls import url from django.contrib import admin 同时pattrerns()已经废弃 替换为urlpatterns = [ url(r'^time/plus/(\d{1,2})/$', hours_ahead) ]
这里,我们修改了两个地方。 首先,在顶部导入current_datetime函数; 其次,也是比较重要的:添加URL模式来映射URL中的/time/和新视图。 理解了么?
写好视图并且更新URLconf之后,运行命令python manage.py runserver以启动服务,在浏览器中输入http://127.0.0.1:8000/time/。 你将看到当前的日期和时间。
3.0的是URL-->views.py-->**.html文件,接着更新数据库, python manage.py makemigrations **文件夹(这个文件夹是你放model.py和views.py的文件夹)接着是:python manage.py migrate,这样再重新运行Python manage.py runserver即可,这个是3.0版本的运行方式
Django时区
视乎你的机器,显示的日期与时间可能和实际的相差几个小时。 这是因为Django是有时区意识的,并且默认时区为America/Chicago。 (它必须有个值,它的默认值是Django的诞生地:美国/芝加哥)如果你处在别的时区,你需要在settings.py文件中更改这个值。请参见它里面的注释,以获得最新世界时区列表。
回楼上,视乎不是“似乎”的意思。如果是‘似乎’的意思,那这句话就乱了。视乎是“要看”的意思,举例:短期表现将视乎内地股市表现,这句话经常看见。翻译大哥有炒股的可能。。 :)
# Internationalization # https://docs.djangoproject.com/en/1.11/topics/i18n/ # 默认语言与时区 # LANGUAGE_CODE = 'en-us' # # TIME_ZONE = 'UTC' # # USE_I18N = True # # USE_L10N = True # # USE_TZ = True # 修改版 LANGUAGE_CODE = 'zh-hans' TIME_ZONE = 'Asia/Shanghai' USE_I18N = True USE_L10N = True USE_TZ = False
URL配置和松耦合
现在是好时机来指出Django和URL配置背后的哲学: 松耦合 原则。 简单的说,松耦合是一个 重要的保证互换性的软件开发方法。
Django的URL配置就是一个很好的例子。 在Django的应用程序中,URL的定义和视图函数之间是松 耦合的,换句话说,决定URL返回哪个视图函数和实现这个视图函数是在两个不同的地方。 这使得 开发人员可以修改一块而不会影响另一块。
例如,考虑一下current_datetime视图。 如果我们想把它的URL 从原来的 /time/ 改变到 /currenttime/ ,我们只需要快速的修改一下URL配置即可, 不用担心这个函数的内部实现。 同样的,如果我们想要修改这个函数的内部实现也不用担心会影响 到对应的URL。
此外,如果我们想要输出这个函数到 一些 URL, 我们只需要修改URL配置而不用 去改动视图的代码。 在这个例子里,current_datetime被两个URL使用。 这是一个故弄玄虚的例子,但这个方法迟早会用得上。
urlpatterns = patterns('',
('^hello/$', hello),
('^time/$', current_datetime),
('^another-time-page/$', current_datetime),
)
松耦合应该是板块化设计的意思。在这个地方体现为将URLconf抽象为一个目录,而views里面的函数都是该目录下的具体内容。通过对目录的指定而调用不同的内容,内容的变化不会引起目录的变化,目录的变化不会引起内容的变化。
URLconf和视图是松耦合的。 我们将在本书中继续给出这一重要哲学的相关例子。
第三个视图 动态URL
在我们的current_datetime 视图范例中,尽管内容是动态的,但是URL ( /time/ )是静态的。 在 大多数动态web应用程序,URL通常都包含有相关的参数。 举个例子,一家在线书店会为每一本书提供一个URL,如:/books/243/、/books/81196/。
让我们创建第三个视图来显示当前时间和加上时间偏差量的时间,设计是这样的: /time/plus/1/ 显示当前时间+1个小时的页面 /time/plus/2/ 显示当前时间+2个小时的页面 /time/plus/3/ 显示当前时间+3个小时的页面,以此类推。
新手可能会考虑写不同的视图函数来处理每个时间偏差量,URL配置看起来就象这样:
urlpatterns = patterns('',
('^time/$', current_datetime),
('^time/plus/1/$', one_hour_ahead),
('^time/plus/2/$', two_hours_ahead),
('^time/plus/3/$', three_hours_ahead),
('^time/plus/4/$', four_hours_ahead),
)
很明显,这样处理是不太妥当的。 不但有很多冗余的视图函数,而且整个应用也被限制了只支持 预先定义好的时间段,2小时,3小时,或者4小时。 如果哪天我们要实现 5 小时,我们就 不得不再单独创建新的视图函数和配置URL,既重复又混乱。 我们需要在这里做一点抽象,提取 一些共同的东西出来。
关于漂亮URL的一点建议
如果你有其它web平台的开发经验(如PHP或Java),你可能会想:嘿!让我们用查询字符串参数吧! 就像/time/plus?hours=3里面的小时应该在查询字符串中被参数hours指定(问号后面的是参数)。
你 可以 在Django里也这样做 (如果你真的想要这样做,我们稍后会告诉你怎么做), 但是Django的一个核心理念就是URL必须看起来漂亮。 URL /time/plus/3/ 更加清晰, 更简单,也更有可读性,可以很容易的大声念出来,因为它是纯文本,没有查询字符串那么 复杂。 漂亮的URL就像是高质量的Web应用的一个标志。
Django的URL配置系统可以使你很容易的设置漂亮的URL,而尽量不要考虑它的 反面 。
那么,我们如何设计程序来处理任意数量的时差? 答案是:使用通配符(wildcard URLpatterns)。正如我们之前提到过,一个URL模式就是一个正则表达式。因此,这里可以使用d+来匹配1个以上的数字。
urlpatterns = patterns('',
# ...
(r'^time/plus/\d+/$', hours_ahead),
# ...
)
这里使用# …来表示省略了其它可能存在的URL模式定义。 (见上)
这个URL模式将匹配类似 /time/plus/2/ , /time/plus/25/ ,甚至 /time/plus/100000000000/ 的任何URL。 更进一步,让我们把它限制在最大允许99个小时, 这样我们就只允许一个或两个数字,正则表达式的语法就是 \d{1,2} :
(r'^time/plus/\d{1,2}/$', hours_ahead),
备注
在建造Web应用的时候,尽可能多考虑可能的数据输入是很重要的,然后决定哪些我们可以接受。 在这里我们就设置了99个小时的时间段限制。
另外一个重点,正则表达式字符串的开头字母“r”。 它告诉Python这是个原始字符串,不需要处理里面的反斜杠(转义字符)。 在普通Python字符串中,反斜杠用于特殊字符的转义。比如n转义成一个换行符。 当你用r把它标示为一个原始字符串后,Python不再视其中的反斜杠为转义字符。也就是说,“n”是两个字符串:“”和“n”。由于反斜杠在Python代码和正则表达式中有冲突,因此建议你在Python定义正则表达式时都使用原始字符串。 从现在开始,本文所有URL模式都用原始字符串。
现在我们已经设计了一个带通配符的URL,我们需要一个方法把它传递到视图函数里去,这样 我们只用一个视图函数就可以处理所有的时间段了。 我们使用圆括号把参数在URL模式里标识 出来。 在这个例子中,我们想要把这些数字作为参数,用圆括号把 \d{1,2} 包围起来:
(r'^time/plus/(\d{1,2})/$', hours_ahead), 貌似要用双引号才有用,我的版本是1.6.5 (r"^time/plus/(\d{1,2})/$", hours_ahead),
上面提到的path('time/plus/<int:offset>/', views.hours_ahead),里面的offset怎么来?答:后面会定义一个视图函数,offset就是要传进去的参数。
(r'^time/plus/(\d{1,2})/$', hours_ahead),
最终的URLconf包含上面两个视图,如:
Django1.2.1中,下面的正则好像不好用了。必须指定最后正则要接收的参数名才能正常运行。 (r'^time/plus/(\d{1,2})/$', hours_ahead), ↓ (r'^time/plus/(?P<poll_id>\d{1,2})/$', hours_ahead),
esmiles的评注很有用,Django1.3.1中一开始也是不行,修改成 (r'^time/plus/(?P<offset>\d{1,2})/$', hours_ahead),就好了。后来发现例子中的写法也是可以的,但1和2之间不能有空格。正则表达式没怎么学过,不知是不是一个BUG。
我的是 Django 1.31, 用(r'^time/plus/(\d{1,2})/$', hours_ahead)不好使,错误是'tuple' object is not callable。 修改成(r'^time/plus/(?P<offset>\d{1,2})/$', hours_ahead)后,还是不好使啊
1.4.1 这样操作出现: TypeError at /time/plus/3/ hours_ahead() takes exactly 2 arguments (1 given)
我的django1.8是这样写的 urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^hello/$', "views.hello"), url(r'^time/$', "views.current_datetime"), url(r'^time/plus/(\d{1,2})/$', "views.hours_ahead"), ]
我是把url改成url(r'^timeplus/(\d{1,2})/', hours_ahead),才显示;用url(r'^time/plus/(\d{1,2})/', hours_ahead)一直显示time的html页面为什么??
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),
)
这个例子中,我们先写了URLpattern ,然后是视图,但是在前面的例子中, 我们先写了视图,然后是URLpattern 。 哪一种方式比较好?
嗯,怎么说呢,每个开发者是不一样的。
如果你是喜欢从总体上来把握事物(注: 或译为“大局观”)类型的人,你应该会想在项目开始 的时候就写下所有的URL配置。
如果你从更像是一个自底向上的开发者,你可能更喜欢先写视图, 然后把它们挂接到URL上。 这同样是可以的。
最后,取决与你喜欢哪种技术,两种方法都是可以的。 (见上)
hours_ahead 和我们以前写的 current_datetime 很象,关键的区别在于: 它多了一个额外参数,时间差。 以下是view代码:
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,匹配修改成 (r'^time/plus/(?P<poll_id>\d{1,2})/$', hours_ahead), #views.py 修改成 def hours_ahead(request, poll_id): try: poll_id = int(poll_id) except ValueError: raise Http404("un support value") dt = datetime.datetime.now() + datetime.timedelta(hours=poll_id) html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (poll_id, dt) return HttpResponse(html)
因为一个个人问题,导致我的hours_ahead经常显示没定义,要记得在urls.py中引用,from mysite.views.py import hello,hours_ahead.
keith 2011-01-04 21:02:24 因为一个个人问题,导致我的hours_ahead经常显示没定义,要记得在urls.py中引用,from mysite.views.py import hello,hours_ahead. |直接 from mysite.views import * 可以么?
呼呼~试了好久才成功。#urls.py部分改成:(r'^time/plus/(?P<offset>\d{1,2})/$','mysite.views.hours_ahead')。即使上面用了from mysite.views import hello,hours_ahead似乎还是需要写上mysite.views后面跟上hours_ahead.
dt = datetime.datetime.now() + datetime.timedelta(hours=offset) 当前时间+5 ?默认是小时么 不能是分钟呀?
offset参数是你在url最后边所写的数字部分,{1,2}设定你的参数是1到两位数。如:~/time/plus/1/或者/time/plus/55,如果写的是二位以上的则会返回一个404页面。在页面上显示的是In X hours,it will be 所显示的是当前时间+X后所得的日期。
让我们逐行分析一下代码:
视图函数, hours_ahead , 有 两个 参数: request 和 offset . (见上)
用IE8进行的测试,在urls.py当中,代码如下: url(r'^time/$',time), url(r'^time/plus/(\d{1,2})/$', hours_ahead), 注意第一行当中的$符号,要不总是显示time的信息,并且删除一下浏览器的浏览历史记录信息
不得不说Python调用参数真方便。换做C不知道要加多少行。起码就要额外定义一个全局量提取URL里用户输入的参数,而这个输入的参数又需要通过一个函数转义。然后还要把srtings变成int或者unit。Python里面似乎可以通过()直接提取出正则表达式里的参数。不过还是有点疑问,参数多了怎么匹配?如果我不止一组(),或是不止一个参数呢?还是不能从C语言的思维跳出啊。顺带一提,offset是提取(r'^***/(\d{1,2}/$),***)里的参数。
request 是一个 HttpRequest 对象, 就像在 current_datetime 中一样. 再说一次好了: 每一个视图 总是 以一个 HttpRequest 对象作为 它的第一个参数。 (见上)
offset 是从匹配的URL里提取出来的。 例如:如果请求URL是/time/plus/3/,那么offset将会是3;如果请求URL是/time/plus/21/,那么offset将会是21。请注意:捕获值永远都是字符串(string)类型,而不会是整数(integer)类型,即使这个字符串全由数字构成(如:“21”)。
有同样的疑问。不过查阅上下文,得到的解答应是: "正则表达式也是用圆括号来从文本里 提取 数据的"。 因而,urls文件中的(r'^time/plus/(\d{1,2})/$', hours_ahead)语句定义了要传递的参数(\d{1,2}),传递给hours_ahead作为其第二个参数,即offset。
若把 (r'^time/plus/(\d{1,2})/$', hours_ahead)改成 (r'^time/plus/\d{1,2}/$', hours_ahead) 會拋出錯誤,所以是用 "()"來指定要丟給 view.py 的參數。
若把 (r'^time/plus/(\d{1,2})/$', hours_ahead)改成 (r'^time/plus/\d{1,2}/$', hours_ahead) 會拋出錯誤,所以是用 "()"來指定要丟給 view.py 的參數。多個參數也可以用一樣的方法指定。
那是不是如果我要传递多个参数的话,从client端传递过来的还是一个字符串,只不过我可以用正则表达式从中提取出不同的内容,然后用()分别传递给试图函数的第一个,第二个参数。这样理解对吗?
这里并不是通过正则来传参的吧,关键是正则外面的那个圆括号。 例如这句:(r'^time/plus/(\d{1,2})/$', hours_ahead) 如果是标准的正则来写的话应该是: (r'^time/plus/\d{1,2}/$', hours_ahead) 相比原文少了那个圆括号,这样也的确出现了错误。所以传参是通过这里的圆括号来进行的。
里边说到提取参数: 我们只用一个视图函数就可以处理所有的时间段了。 我们使用圆括号把参数在URL模式里标识 出来。 在这个例子中,我们想要把这些数字作为参数,用圆括号把 \d{1,2} 包围起来: 6 (r'^time/plus/(\d{1,2})/$', hours_ahead), 如果你熟悉正则表达式,那么你应该已经了解,正则表达式也是用圆括号来从文本里 提取 数据的
offset 是从匹配的URL里提取出来的,捕获值永远都是字符串(string)类型,而不会是整数(integer)类型,即使这个字符串全由数字构成(如:“21”)。
开始不能理解为什么会传参,于是找到官方文档查了关于urls部分的说明,有这样一段话:"To capture a value from the URL, just put parenthesis around it." 接着看下去还有这句:"non-named regular-expression groups (via parenthesis) to capture bits of the URL and pass them as positional arguments to a view. "大概明白django可能是定义了某个函数,使得用括号括起来的部分可以作为参数按顺序传递下去 于是翻看了django的程序部分,在urls里有个resolvers.py,其中有一个函数我猜可能是我想要的一部分吧: def resolve(self,path): match = self.regex.search(path) if match: # If there are any named groups, use those as kwargs, ignoring # non-named groups. Otherwise, pass all non-named arguments as # positional arguments. kwargs = match.groupdict() args = () if kwargs else match.groups() # In both cases, pass any extra_kwargs as **kwargs. kwargs.update(self.default_args) return ResolverMatch(self.callback, args, kwargs, self.name) 因为水平有限,不能很好理解关于整个定义部分,但也似乎理解了一点,不知道对不对,望各路大神指点。
(从技术上来说,捕获值总是Unicode objects,而不是简单的Python字节串,但目前不需要担心这些差别。)
在这里我们命名变量为 offset ,你也可以任意命名它,只要符合Python 的语法。 变量名是无关紧要的,重要的是它的位置,它是这个函数的第二个 参数 (在 request 的后面)。 你还可以使用关键字来定义它,而不是用 位置。
这个地方原文的意思是它“必须”是这个函数的第二个参数(在request的后面)。你还可以使用关键字参数来代替位置参数(详情在第八章中讨论)。。中文翻译过来没有必须的意思,理解上有点乖乖的
我们在这个函数中要做的第一件事情就是在 offset 上调用 int() . 这会把这个字符串值转换为整数。
请留意:如果你在一个不能转换成整数类型的值上调用int(),Python将抛出一个ValueError异常。如:int(‘foo’)。在这个例子中,如果我们遇到ValueError异常,我们将转为抛出django.http.Http404异常——正如你想象的那样:最终显示404页面(提示信息:页面不存在)。
机灵的读者可能会问: 我们在URL模式中用正则表达式(d{1,2})约束它,仅接受数字怎么样?这样无论如何,offset都是由数字构成的。 答案是:我们不会这么做,因为URLpattern提供的是“适度但有用”级别的输入校验。万一这个视图函数被其它方式调用,我们仍需自行检查ValueError。 实践证明,在实现视图函数时,不臆测参数值的做法是比较好的。 松散耦合,还记得么?
机灵的读者可能会问:既然我们在URLpattern里使用了正则表达式(\d{1,2})来匹配数字,那么无论如何,offset都是由数字构成的,那又怎么会碰到ValueError异常呢? 我们当然不会碰到这个异常,因为URLpattern提供了适度但有用的输入校验,但我们仍需自行检查ValueError,以防这个视图函数以其它方式被调用。在实现视图函数时,不是臆测参数值的做法是比较好的。松散耦合,还记得么?
由上文可知:捕获值永远都是字符串(string)类型,而不会是整数(integer)类型,即使这个字符串全由数字构成(如:“21”)。所以offset获取的肯定是字符串不是么?int()转换后变为整数。因此, 我们当然不会碰到这个异常(ValueError异常)不是因为正则的约束,而是int()的缘故吧?
由上文可知:捕获值永远都是字符串(string)类型,而不会是整数(integer)类型,即使这个字符串全由数字构成(如:“21”)。所以offset获取的肯定是字符串不是么?int()转换后变为整数。因此, 我们当然不会碰到这个异常(ValueError异常)不是因为正则的约束,而是int()的缘故吧?或者译文是指正则获取的肯定是整数字符串,所以int()转换后肯定也是整数而不会遇到ValueError异常?
由上文可知:捕获值永远都是字符串(string)类型,而不会是整数(integer)类型,即使这个字符串全由数字构成(如:“21”)。所以offset获取的肯定是字符串不是么?int()转换后变为整数。因此, 我们当然不会碰到这个异常(ValueError异常)不是因为正则的约束,而是int()的缘故吧?或者译文是指正则获取的肯定是整数字符串,所以int()转换后肯定也是整数而不会遇到ValueError异常?另外,对于译文说的“但我们仍需自行检查ValueError,以防这个视图函数以其它方式被调用”能举个例子吗?
但我们仍需自行检查ValueError,以防这个视图函数以其它方式被调用。在实现视图函数时,不是臆测参数值的做法是比较好的。松散耦合,还记得么? 我也想知道“以防这个视图函数以其它方式被调用”,这个其它方式,能举个例吗
“以防这个视图函数以其它方式被调用”:我的理解是,比如在url.py里面的代码是"(r'^time/plus/([a-z])/$', hours_ahead),"这样视图hours_ahead“以其它方式被调用”。从语法及调用上讲,在url.py中并没有任何问题,从而也体现出了“松耦合”。 下面是我基于Chika的翻译的小修改版,感谢Chika翻译的已经很好了。 机灵的读者可能会问:既然我们在URLpattern里使用了正则表达式(\d{1,2})来匹配数字,那么无论如何,offset都是由数字构成的,那又怎么会碰到ValueError异常呢? 我们当然不会碰到这个异常,因为URLpattern提供了适度但有用的输入校验,(\d{1,2})保证了offset肯定为数字。但调用hours_ahead的正则表达式可写成任何内容,本身可以不进行数字匹配,我们仍需自行检查ValueError,以防这个视图函数以其它方式被调用。在实现视图函数时,不是臆测参数值的做法是比较好的。松散耦合,还记得么?
下一行,计算当前日期/时间,然后加上适当的小时数。 在current_datetime视图中,我们已经见过datetime.datetime.now()。这里新的概念是执行日期/时间的算术操作。我们需要创建一个datetime.timedelta对象和增加一个datetime.datetime对象。 结果保存在变量dt中。
这一行还说明了,我们为什么在offset上调用int()——datetime.timedelta函数要求hours参数必须为整数类型。
用hours = offset是应该为了指定hours(小时)这个参数。因为timedelta的参数如果是(hours=0,mins=0,...)之类的hours是第一个参数时可能没错,但是如果hours前有别的什么的参数时,比如(years=0,hours=0,...),导致hours不是第一个参数的时候,不指定参数名会导致bug,该计算小时的时候计算成了年什么的。
这行和前面的那行的的一个微小差别就是,它使用带有两个值的Python的格式化字符串功能, 而不仅仅是一个值。 因此,在字符串中有两个 %s 符号和一个以进行插入的值的元组: (offset, dt) 。
最终,返回一个HTML的HttpResponse。 如今,这种方式已经过时了。
"old-hat" 有两个意思, 一个是out of fashion, 过时了. 还有一个是指something has been brought up many times, 已经说过很多次了. 这里应该是后者
其实个人觉得,说是过时也不算错,因为现在对于字符串格式化,从python3x开始就有新的作为字符串格式化方法format了,这是我的笔记: 字符串格式化方法 定义语法: {fieldname[conversionflag:formatspec]} fieldname是指定参数的数字或关键词,一般为数字/关键词/关键词.属性/字典.[键] conversionflag是指r/s/a,r对于repr,s对应str,a对应ascii formatspec等于[[fill]align][sign][#][0][width][.precision][typecode] 范例 '... {0} ... {1} ... {n}...'.format(1,2, ... n) '... {关键词1} ... {关键词2} ... {关键词n}...'.format(关键词1=值,关键词2=值, ... 关键词n=值) '... {字典名.[键]} ... {关键词.属性} ...'.format(字典,关键词=对象) //可以通过字典名和键返回format内对于字典键的值,也可以通过关键词调用对象的属性 现在虽然没有取消字符串格式化,但是字符串格式化方法已经覆盖了将近所有的字符串格式化,而且能够实现更加多的功能,在未来,字符串格式化可能会成为过去
在完成视图函数和URL配置编写后,启动Django开发服务器,用浏览器访问 http://127.0.0.1:8000/time/plus/3/ 来确认它工作正常。 然后是 http://127.0.0.1:8000/time/plus/5/ 。再然后是 http://127.0.0.1:8000/time/plus/24/ 。最后,访问 http://127.0.0.1:8000/time/plus/100/ 来检验URL配置里设置的模式是否只 接受一个或两个数字;Django会显示一个 Page not found error 页面, 和以前看到的 404 错误一样。 访问URL http://127.0.0.1:8000/time/plus/ (没有 定义时间差) 也会抛出404错误。
/time/plus/100/没有404,估计是你的正则表达式多写的加号没有去掉,\d+表示至少1个数字,\d{1,2}表示只能1~2个数字,\d{1,2}+就是至少1~2个数字了(多了也可以)
urls.py中,原为(r'^time/plus/\d+/$', hours_ahead),应该是(r'^time/plus/(\d+)/$', hours_ahead),少了对儿括号
Django 漂亮的出错页面
花几分钟时间欣赏一下我们写好的Web应用程序,然后我们再来搞点小破坏。 我们故意在 views.py 文件中引入一项 Python 错误,注释掉 hours_ahead 视图中的 offset = int(offset) 一行。
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)
启动开发服务器,然后访问 /time/plus/3/ 。你会看到一个包含大量信息的出错页,最上面 的一条 TypeError 信息是: "unsupported type for timedelta hours component: unicode" .
怎么回事呢? 是的, datetime.timedelta 函数要求 hours 参数必须为整型, 而我们注释掉了将 offset 转为整型的代码。 这样导致 datetime.timedelta 弹出 TypeError 异常。
这个例子是为了展示 Django 的出错页面。 我们来花些时间看一看这个出错页,了解一下其中 给出了哪些信息。
以下是值得注意的一些要点:
在页面顶部,你可以得到关键的异常信息: 异常数据类型、异常的参数 (如本例中的 "unsupported type" )、在哪个文件中引发了异常、出错的行号等等。
在关键异常信息下方,该页面显示了对该异常的完整 Python 追踪信息。 这类似于你在 Python 命令行解释器中获得的追溯信息,只不过后者更具交互性。 对栈中的每一帧,Django 均显示了其文件名、函数或方法名、行号及该行源代码。
点击该行代码 (以深灰色显示),你可以看到出错行的前后几行,从而得知相关上下文情况。
点击栈中的任何一帧的“Local vars”可以看到一个所有局部变量的列表,以及在出错 那一帧时它们的值。 这些调试信息相当有用。
注意“Traceback”下面的“Switch to copy-and-paste view”文字。 点击这些字,追溯会 切换另一个视图,它让你很容易地复制和粘贴这些内容。 当你想同其他人分享这些异常 追溯以获得技术支持时(比如在 Django 的 IRC 聊天室或邮件列表中),可以使用它。
你按一下下面的“Share this traceback on a public Web site”按钮,它将会完成这项工作。 点击它以传回追溯信息至http://www.dpaste.com/,在那里你可以得到一个单独的URL并与其他人分享你的追溯信息。
接下来的“Request information”部分包含了有关产生错误的 Web 请求的大量信息: GET 和 POST、cookie 值、元数据(象 CGI 头)。 在附录H里给出了request的对象的 完整参考。
Request信息的下面,“Settings”列出了 Django 使用的具体配置信息。 (我们已经提及过ROOT_URLCONF,接下来我们将向你展示各式的Django设置。 附录D覆盖了所有可用的设置。)
Django 的出错页某些情况下有能力显示更多的信息,比如模板语法错误。 我们讨论 Django 模板系统时再说它们。 现在,取消 offset = int(offset) 这行的注释,让它重新正常 工作。
不知道你是不是那种使用小心放置的 print 语句来帮助调试的程序员? 你其实可以用 Django 出错页来做这些,而不用 print 语句。 在你视图的任何位置,临时插入一个 assert False 来触发出错页。 然后,你就可以看到局部变量和程序语句了。 这里有个使用hours_ahead视图的例子:
def hours_ahead(request, offset):
try:
offset = int(offset)
except ValueError:
raise Http404()
dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
assert False
html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt)
return HttpResponse(html)
最后,很显然这些信息很多是敏感的,它暴露了你 Python 代码的内部结构以及 Django 配置,在 Internet 上公开这信息是很愚蠢的。 不怀好意的人会尝试使用它攻击你的 Web 应用程序,做些下流之事。 因此,Django 出错信息仅在 debug 模式下才会显现。 我们稍后 说明如何禁用 debug 模式。 现在,你只要知道 Django 服务器在你开启它时默认运行在 debug 模式就行了。 (听起来很熟悉? 页面没有发现错误,如前所述,工作正常。)
"The “Page not found” errors, described earlier in this chapter, work the same way.)" 前面提到的“Page not found” 错误工作原理也是一样的
下一章
目前为止,我们已经写好了视图函数和硬编码的HTML。 在演示核心概念时,我们所作的是为了保持简单。但是在现实世界中,这差不多总是个坏主意。
硬编码一般指在代码中写死的,与它相对的是配置项,可以在程序发布后进行修改的 来自:https://zhidao.baidu.com/question/433037849795897284.html