转载请注明来源地址和原作者(CFishHome)
前沿
上一节的学前准备工作和第一个小牛试刀的Django项目学习,让我们对Django开发越来越感兴趣了。正所谓趁热打铁,让我们继续来学习网站开发必备的视图函数和URL映射等知识,跟着步伐一起学习,我相信你会收获很多。噔~噔,新闻播报时间:9月12-9月16有两个超强台风在广东湛江登陆,沿途影响众多城市,包括深圳!!所以很遗憾,前几天打算和舍友去深圳游玩的计划泡汤了,也只能推迟几天前往深圳度中秋、看月亮了~
DEBUG模式
无论是使用命令行还是Pycharm创建Django项目工程,settings.py文件的DEBUG都默认设置为True,所以默认是开启了DEBUG模式。如下图所示:
开启DEBUG模式有以下好处:
1.我们可以发现,在Django开发时,频繁修改文件代码,然后要关闭项目,再重启项目才能测试我们修改的代码。但是如果开启了DEBUG模式,那么以后我们修改了Django项目的代码,然后按下了ctrl+s,那么Django就会自动的给我们重启项目,不需要手动关闭再重启。
2.如果开启了DEBUG模式,那么以后Django项目中的代码出现bug了,那么在浏览器和控制台会打印出错信息。
3.在实际将项目发布到网上给其他用户使用时,禁止开启DEBUG模式,因为前面说了入宫出现bug会在浏览器和控制台打印出错信息,这无疑把代码泄露在网上,会有很大的安全隐患。
4.如果DEBUG设置为False,那么必须设置ALLOWED_HOSTS。前一篇说过,如果将host设置为0.0.0.0,那么只能通过ALLOWED_HOSTS设置的IP地址进行访问该项目,也可以设置多个IP地址。ALLOWED_HOSTS字段如下图位置:
URL分发器
我们在学习前先回顾下我们上一篇做了什么。上一篇我们首先在Pycharm创建了一个名为first_project的Django项目,然后在CMD使用命令创建了一个名为my_app的app应用。注意,上篇因测试需要修改了IP地址和端口号,所以这里我将项目的IP地址和端口号修改回127.0.0.1:8000,说明访问这个IP就可以访问我们的项目了。整体框架如下图所示:
视图
视图其实就是视图函数,它一般都写在 app 的 views.py 文件中,也就是我们my_app包里的views.py文件。并且视图函数的第一个参数永远都是 request (一个HttpRequest)对象。这个对象存储了请求过来的所有信息,包括携带的参数以及一些头部信息等。在视图中,一般是完成逻辑相关的操作。比如这个请求是添加一篇博客,那么在视图函数可以通过request来接收到这些数据,然后存储到数据库中,最后再把函数执行的结果返回给浏览器。视图函数的返回结果必须是 HttpResponseBase 对象或者子类的对象。
我们打开my_app的views.py文件,添加以下代码:
from django.http import HttpResponse
# book_list是我们定义的一个视图函数,第一个参数必须是request对象,并且该函数返回必须是 HttpResponseBase 对象或者子类的对象。
def book_list(request):
return HttpResponse("书籍列表!")
上面视图函数返回的 HttpResponse("书籍列表!")只是单纯的在网页上输出"书籍列表!"文本内容。
URL映射
视图函数写完后,我们怎么实现让用户在浏览器中输入一个URL就可以访问到我们刚才写的视图函数,即用户在浏览器一输入某URL,网页就显示"书籍列表!"文本内容。
URL映射原理:用户在浏览器输入了某个 URL ,请求到我们的网站的时候, django 会从项目的 urls.py 文件中寻找对应的视图。为什么会是在urls.py文件中寻找映射呢?这是因为在"settings.py"文件中配置了"ROT_URLCONF"为"urls.py"。在 urls.py 文件中有一个 urlpatterns 变量,以后 django 就会从这个变量中读取所有的匹配规则。匹配规则需要使用 django.urls.path 函数进行包裹,这个函数会根据传入的参数返回 URLPattern 或者是 URLResolver 的对象。
修改first_project项目的 urls.py 文件代码,示例代码如下:
from django.contrib import admin
from django.urls import path
from my_app import views # 导入my_app包的views.py模块
urlpatterns = [
path(‘admin/‘, admin.site.urls),
path(‘book/‘, views.book_list)
]
运行first_project项目,在浏览器输入127.0.0.1:8000/book,访问成功!如下图所示(图片左下角显示了"书籍列表!"文本内容):
到了这里朋友们可能会好奇如果输入127.0.0.1:8000会怎么样?满足你的好奇心,结果如下:
我的天!我按照上一篇的流程可以访问的啊,怎么现在不彳亍了。其实当新添加了第一个URL映射之后需要注意的是主网页127.0.0.1:8000的网页404丢失了,这是因为如果刚开始创建的项目,若还未添加过URL映射,那么默认Django的底层提供一个就是那个火箭??页面来映射,但若添加了,那么就无法继续映射那个火箭??页面了,因为看urlpatterns变量其实都没有映射空URL,即127.0.0.1:8000为空URL。
为URL传递参数
为URL传递参数有三种方式:
1.URL中添加参数
2.查询字符串传递参数
3.指定默认的参数
URL中添加参数
有时候, url 中包含了一些参数需要动态调整。比如简书某篇文章的详情页的url,是 https://www.jianshu.com/p/a5aab9c4978e 后面的 a5aab9c4978e 就是这篇文章的 id ,那么简书的文章详情页面的url就可以写成 https://www.jianshu.com/p/<id> ,其中id就是文章的id。那么如何在 django 中实现这种需求呢。这时候我们可以在 path 函数中,使用尖括号的形式来定义一个参数,也可以多个参数。比如我现在想要获取一本书籍的详细信息,那么应该在 url 中指定这个参数。first_project项目urls.py文件的示例代码如下:
from django.contrib import admin
from django.urls import path
from book import views
urlpatterns = [
path(‘admin/‘, admin.site.urls),
path(‘book/‘,views.book_list),
path(‘book/<book_id>/‘,views.book_detail) # <book_id>就是参数
]
采用在URL中使用变量的方式,在path函数的第一个参数中,使用“<参数名>”的方式可以传递参数,然后在视图函数中也要写一个函数来进行映射,视图函数中的参数必须和URL中的参数名称保持一致,不然就找不到这个参数(视图函数第一个参数是request,那么第二个参数就是book_id)。
而my_app包的views.py 中的代码如下:
# 该视图函数与‘book/<book_id>/‘进行URL映射,并且视图函数第二个参数必须同名
def book_detail(request,book_id):
text = "您输入的书籍的id是:%s" % book_id
return HttpResponse(text)
运行结果如下:
对于多个参数也同样类似,这里不再测试。只不过在URL中添加多个参数,然后视图函数添加多个同名参数来接收。
查询字符串传递参数
另一种方式是通过查询字符串的方式传递一个参数过去。在设置URL时,不需要单独的匹配查询字符串的部分,只需要在视图函数中使用request.GET.get(‘参数名称‘)的方式来获取。因为查询字符串使用的是“GET”请求,所以我们通过“request.GET”来获取参数。
first_project项目的urls.py文件的示例代码如下:
urlpatterns = [
path(‘admin/‘, admin.site.urls),
path(‘book/‘,views.book_list),
path(‘book/<int:book_id>/‘,views.book_detail), # <book_id>就是参数,注意book_id前面还添加了个int转换器,这里只要我们知道这是限制输入的id只能是整型即可,后面会详细讲解转换器的作用。
path(‘book/pub/‘,views.book_pub)
]
在 my_app包中的views.py 后面添加如下代码:
def book_pub(request):
pub_id = request.GET.get("id")
text = "您输入的出版社id是:%s" % pub_id
return HttpResponse(text)
以后在浏览器输入127.0.0.1:8000/book/pub/?id=1 即可将参数传递过去。
运行结果如下:
我们做个小测试,如果将转换器Int去掉的话,我们还能成功访问到嘛?将urls.py文件代码修改如下:
urlpatterns = [
path(‘admin/‘, admin.site.urls),
path(‘book/‘,views.book_list),
path(‘book/<book_id>/‘,views.book_detail),
path(‘book/pub/‘,views.book_pub)
]
运行结果如下:
通过上图可以发现,跟我们预期的不太一样,我们在浏览器输入的URL(http://127.0.0.1:8000/book/pub/?id=200) 被book_detail视图函数捕获了,这说明pub后面的所有字符串都被认为是传递到book_detail视图函数。
指定默认的参数
使用 path 后,在path的第一个参数可以包含参数,而有时候想指定默认的参数,这时候可以通过以下方式来完成,以下代码仅供理解默认参数的使用,在我们的实际项目中没有此代码。
from django.urls import path
from . import views
urlpatterns = [
path(‘blog/‘, views.page),
path(‘blog/page<int:num>/‘, views.page),
]
# View (in blog/views.py)
def page(request, num=1):
# Output the appropriate page of blog entries, according to num.
上面‘blog/page<int:num>/‘,参数前面多了个page,代表输入URL时需要添加page,例如:’127.0.0.1:8000/blog/page100‘。所欲,如果你只写’127.0.0.1:8000/blog/page‘,那么将使用默认参数,num值为1。
默认参数的使用规则如下:
1.当用户访问一个URL不含有变量的时候,映射到视图函数
并且视图函数的形参有一个默认参数含有值,视图函数就直
接使用这个默认参数。
2.当用户访问一个URL含有变量的时候,映射到视图函数并
且视图函数的形参有一个默认参数含有值,视图函数就不使
用默认参数的值,而是采用URL匹配规则传进来的值。
总结:其实上面的默认函数使用规则和编程语言函数的默认
参数使用规则类似。
转换器
前一节我们简单使用了int转换器将同级的两种传递参数的方式区分开来,不然查询字符串方式会被第一种传递参数方式所捕获。
我们的转换器是用在path函数中,所以有必要简单介绍下path函数,这里只简单介绍第一个参数,后面会详细讲path函数的使用方法。
path函数签名如下:
path(route,view,name=None,kwargs=None)
route 参数: url 的匹配规则。这个参数中可以指定 url 中需要传递的参数,比如在访问文章详情页的时候,可以传递一个 id 。传递参数是通过 <> 尖括号来进行指定的。并且在传递参数的时候,可以指定这个参数的数据类型,比如文章的 id 都是 int 类型,那么可以这样写 <int:id> ,以后匹配的时候,就只会匹配到 id 为 int 类型的 url ,而不会匹配其他的 url ,并且在视图函数中获取这个参数的时候,就已经被转换成一个 int 类型了。
其中还有几种常用的转换器类型:
1.str:非空的字符串类型。默认的转换器。但是不能包含斜杠。
2.int:匹配任意的零或者正数的×××。到视图函数中就是一个int类型。
3.slug:由英文中的横杠 - ,或者下划线 _ 连接英文字符或者数字而成的字符串。
4.uuid:匹配 uuid 字符串。
5.path:匹配非空的英文字符串,可以包含斜杠。
Tips:通过from django.urls import converters可以导入定义转换器的模块。
下面重点介绍int、str、uuid转换器,而slug和path转换器不再解释。
str转换器
str转换器是默认的转换器,代表如果在参数前面不添加任何东西,那么将默认采用str转换器。
在converters模块中对str转换器的定义如下图:
其实说白了也就是一个类,然后定义了一个正则表达式,对传递的参数进行正则匹配。
int转换器
在converters模块中对int转换器的定义如下图:
从类的定义中可以看出,它是匹配一个0-9的任意一个或多个以上的数字。
uuid转换器
UUID 是 通用唯一识别码(Universally Unique Identifier)的缩写,每个人都可以创建不与其它人冲突的UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。目前最广泛应用的UUID,是微软公司的全局唯一标识符(GUID)。全局唯一标识符(GUID,Globally Unique Identifier)是一种由算法生成的二进制长度为128位的数字标识符。GUID的总数达到32^128个,所以随机生成两个相同GUID的可能性极小,但并不为0。GUID的格式为:"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",其中每个 x 是 0-9 或 a-f 范围内的一个4位十六进制数,所以每个x代表4个二进制位,所以4*32=128个二进制位,即GUID的总数达到32^128个。例如:6F9619FF-8B86-D011-B42D-00C04FC964FF 即为有效的 GUID 值。
在converters模块中对uuidt转换器的定义如下图:
URL中包含另外一个urls模块
在我们的项目中,不可能只有一个 app ,如果把所有的 app 的 views 中的视图都放在 first_project项目的urls.py 中进行映射,肯定会让代码显得非常乱。
就像我们目前的项目一样显得十分混乱,多个book的视图映射都放在一起,如下图:
因此 django 给我们提供了一个方法,可以在 app 内部包含自己的 url 匹配规则,而在项目的 urls.py 中再统一包含这个 app 的 urls 。使用这个技术需要借助 include 函数,对include函数的使用后面会有详细讲解,这里只要知道它的作用即可。
好,现在my_app包里添加一个urls.py文件,代码修改如下:
from django.urls import path
from my_app import views
from django.urls import converters
urlpatterns = [
path(‘‘, views.book_list),
path(‘<int:book_id>/‘, views.book_detail), # <book_id>就是参数
path(‘pub/‘, views.book_pub)
]
然后将first_project项目的urls.py代码修改如下:
from django.contrib import admin
from django.urls import path,include
from my_app import views
from django.urls import converters
urlpatterns = [
path(‘admin/‘, admin.site.urls),
path(‘book/‘, include("my_app.urls"))
]
从上面两个文件代码的修改我们可以这样理解:现在first_project项目的urls.py文件,将’book/‘原本的映射交给了my_app包里的urls.py文件进行内部映射。其实这两个文件之间的映射关系就相当于字符串的拼接,例如:‘book/‘拼接my_app的urls.py文件的‘pub/‘组合成’book/pub/‘,然后再映射到book_pub视图函数。
运行结果如下,完全没有问题,跟分离前一模一样:
Path函数
前面只是简单了解path函数的使用,现在详细学习该函数。
path 函数的定义为:
path(route,view,name=None,kwargs=None) 。
以下对这几个参数进行讲解。
- route 参数: url 的匹配规则。这个参数中可以指定 url 中需要传递的参数,前面已讲解,这个参数不再赘述。
- view 参数:可以为一个视图函数或者是 类视图.as_view() 或者是 django.urls.include() 函数的返回值。
- name 参数:这个参数是给这个 url 取个名字的,这在项目比较大, url 比较多的时候用处很大。
- kwargs 参数:有时候想给视图函数传递一些额外的参数,就可以通过 kwargs 参数进行传递。这个参数接收一个字典。会将foo=bar作为关键字实参传入视图函数,所以视图函数要有形参来接收实参。
比如以下的 url 规则:from django.urls import path from . import views urlpatterns = [ path(‘blog/<int:year>/‘, views.year_archive, kwargs={‘foo‘:‘bar‘}), ]
那么以后在访问 blog/1991/ 这个url的时候,会将{‘foo‘:‘bar‘}作为关键字参数传给 year_archive函数。year_archive视图函数的形参中最后添加一个kwargs参数来接收这个额外的参数。
原文地址:http://blog.51cto.com/12731497/2174887