掘金 后端 ( ) • 2021-06-22 14:21
@charset "UTF-8";.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:16px;color:rgba(46,36,36,.87);overflow-x:hidden}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{margin-bottom:5px;font-size:30px;font-weight:500}.markdown-body h1:before{content:"#";margin-right:10px;color:#1976d2}.markdown-body h2{font-size:28px;font-weight:400;border-left:5px solid #454545;margin-top:20px;padding-left:10px;transition:all .3s ease-in-out}.markdown-body h2:hover{border-color:#1976d2}.markdown-body h3{font-size:24px;font-weight:400;margin-top:15px;padding-bottom:0}.markdown-body h4{font-size:20px;font-weight:500}.markdown-body h5{font-size:16px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body h2:first-letter,.markdown-body h3:first-letter,.markdown-body p:first-letter{text-transform:capitalize}.markdown-body em{text-emphasis:dot;text-emphasis-position:under}.markdown-body img{display:block;margin:0 auto!important;max-width:100%;border-radius:2px;box-shadow:0 2px 4px -1px rgba(0,0,0,.2),0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12)!important}.markdown-body hr{position:relative;width:98%;height:1px;border:none;margin-top:32px;margin-bottom:32px;background-image:linear-gradient(90deg,#ddd,#999,#ddd);overflow:visible}.markdown-body hr:after{content:"";position:absolute;margin:auto;left:0;right:0;bottom:0;top:0;display:inline-block;width:60px;height:20px;background:#fff;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAgCAYAAABgrToAAAADoklEQVRYR82XTYgcRRTHf2933Q1RjAa9eFO8JHoJ8RQVBQ2iBwXBET0YEUTXNVmNQtTpmeqaWV0XNRq/o4KoECSCEPSg4CF+BYUkIIiCoCJCPIhC/Ihh2Z0nVV27VnZnenumW9i6ddV7//frV69fVQurfMgq56NawFTPAU6QyomqXrw6wIZeyhCPebA5buNR+akKyGoAjd6BshthnYdSjqNcRVuOlIUsD2j0SuA94IwuMHdh5ZUykOUBXfSGbmKI54EtAeYIHSZoy5dl4JxvNYBOKdW1KE8BQ8AkVk6WhasWsAiN0TX9gveXQaPP+Aytpc4u+bMI06JNohsYYYYOR2lJWtS3OKDRfcAtQfgDoI6Vo4UCGb0OmAEuDvZvYmVbEd/igC3dzDz7gQu8sPA9kJDK27mBmjqBeLjTg90PDFOjWawFFQd06kZHEfaj3LAIpTRpSXsZ5E06zEYP9sDimnAApYaV2SLZG/wjMeqAkijwW4xQJ5Gf/ZzRC8OW3hiBTGGlURRswW55Bh/Ssxljrwew8l1PQaM14GngvGDzBUKdDsMeTtgU5o8B92PFlUf3YXUrHa7Fys6lBqcCGnX15YQ2A18FyPd7Crd1A3M8C1wdbH4DD3hWeP6IEXbQkG97ajR1HPFnuPP5jFFq1OWX7hl8WM9l1AO648uNfwLk7tytMeogty+xeQ4rO3r6bdcx1nuwOGsHmaXGtPzae4uzGnLH1kQkvpdZGrHjssBZJrL+pqS05KWc8tgITAPXRzYvYOXe/C2OV43eDcRBDtIhoS2f9wzc0Cv8Wls+zoFzUC5zF0U241h5uZtPfptp6OUM8wbK+cH5GEpCS17P3fJei0Z3+npTxryJ8CPzbKMtn/ZyWbkPGl0PuFPkmkjkcb4h4R2ZLwRq1H0ALmvjkf2HwK1Y+T1PY2XABe/sHJ6MxN5lnoSpnC/UGbsTaI5phK2R7x6s3Ffk5YoDOrWm3onwJHBmEP86bPmBrsGaenNoIdnxCH+gPEhLXi0Cl1VBvyPVLSh7gEuC62yAfOIUqabWEaaiucMIk6RyqJ+Q/QM69V26jjW86Gvov/EaoyT8zRCn+Xq7PVrbx0nuYUaO9wM3WAbjCE1NEUw09Um4UV+2OKfYfu5/S19gsAzGKqm6LE5FrShbdS0ku465DjDwKA/oQht19ejqbaEVuRbiLhuHByYLjtUAZpDutzP7cYdHsPJXWbjyNVgFwQoa1WXwf4Jd9YD/Ap80+yE7+u9aAAAAAElFTkSuQmCC);background-repeat:no-repeat;background-size:auto 100%;background-position-x:center}.markdown-body code{font-weight:900;word-break:break-word;border-radius:2px;overflow-x:auto;font-size:.87em;padding:.065em .4em;background-color:#fbe5e1;color:#c0341d}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75;border-radius:0 4px}.markdown-body pre>code{font-weight:400;font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{margin:0 4px;text-decoration:none;color:#027fff;transition:all .3s ease-in-out;padding-bottom:4px;border-bottom:2px solid transparent}.markdown-body a:after{content:"";display:inline-block;width:18px;height:18px;margin-left:4px;vertical-align:middle;background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMiIgaGVpZ2h0PSIyMiI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiMwMjdGRkYiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PHBhdGggZD0iTTkuODE1IDYuNDQ4bDEuOTM2LTEuOTM2YzEuMzM3LTEuMzM2IDMuNTgtMS4yNTkgNS4wMTMuMTczIDEuNDMyIDEuNDMyIDEuNTEgMy42NzYuMTczIDUuMDEzbC0xLjQ1MiAxLjQ1Mi0uOTY4Ljk2OGMtMS4zMzcgMS4zMzYtMy41ODEgMS4yNTktNS4wMTMtLjE3MyIvPjxwYXRoIGQ9Ik0xMS4yNjcgMTUuMzY3bC0xLjkzNiAxLjkzNmMtMS4zMzYgMS4zMzctMy41OCAxLjI2LTUuMDEyLS4xNzMtMS40MzItMS40MzItMS41MS0zLjY3Ni0uMTczLTUuMDEybDEuNDUyLTEuNDUyLjk2OC0uOTY4YzEuMzM2LTEuMzM3IDMuNTgtMS4yNiA1LjAxMi4xNzMiLz48L2c+PC9zdmc+);background-size:cover;background-repeat:no-repeat}.markdown-body a:hover{border-color:#027fff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body a.footnote-backref:after,.markdown-body a.footnote-ref:after,.markdown-body sup a:after{display:none!important}.markdown-body table{margin:0 auto 10px;font-size:12px;width:auto;max-width:100%;overflow:auto;border:2px solid #c6c6c6}.markdown-body table img{box-shadow:none!important}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body del{color:rgba(0,0,0,.6)}.markdown-body blockquote{position:relative;color:#666;padding:5px 23px 1px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:hsla(0,0%,78.4%,.12);transition:all .2s ease-in-out}.markdown-body blockquote:hover{border-color:#1976d2}.markdown-body blockquote:after,.markdown-body blockquote:before{position:absolute;font-size:24px;font-weight:800;line-height:24px;color:#cbcbcb;opacity:.6}.markdown-body blockquote:before{content:"“";top:4px;left:6px}.markdown-body blockquote:after{content:"”";right:8px;bottom:-8px}.markdown-body blockquote>p,.markdown-body blockquote blockquote{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body ul li{margin-bottom:0;list-style:inherit}.markdown-body ol li .task-list-item,.markdown-body ul li .task-list-item{list-style:none}.markdown-body ol li .task-list-item ol,.markdown-body ol li .task-list-item ul,.markdown-body ul li .task-list-item ol,.markdown-body ul li .task-list-item ul{margin-top:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:3px}.markdown-body ol li{padding-left:6px}.markdown-body details{outline:none;border:none;border-left:4px solid #1976d2;padding-left:10px;margin-left:4px}.markdown-body details summary{cursor:pointer;border:none;outline:none;background:#fff;margin:0 -17px}.markdown-body details summary:hover::-webkit-details-marker{color:#1976d2}@media (max-width:720px){.markdown-body h1{font-size:24px}.markdown-body h2{font-size:20px}.markdown-body h3{font-size:18px}}

这是我参与更文挑战的第21天,活动详情查看: 更文挑战


引言

初步完善图书管理系统 中已经完成了后台管理的界面,但这一般是提供管理员来访问的。接下来就要做公共访问的页面了。当我们刚刚在浏览器中输入 http://127.0.0.1:8000/admin/ 之后,浏览器显示出了后台管理的登录页面,那有没有想过这个服务器是怎么给我们找到这个页面并返回呢?/admin/ 是我们想要请求的页面,服务器在收到这个请求之后,就一定对应着一个处理动作,这个处理动作就是帮我们产生页面内容并返回回来,这个过程在 Django 中是由 视图 来做的。

对于 Django 的设计框架 MVT ,用户在 URL 中请求的是 views 视图,视图接收请求后进行处理,并将处理的结果返回给请求者。

Django 中使用视图,一般需要进行两步操作:

  • 定义视图
  • 配置URL

环境

环境名称版本Python3.7.9Django3.1.2

Django 视图

基于函数的视图

视图函数的必须有一个参数,一般叫 request,视图必须返回 HttpResponse 对象,HttpResponse 中的参数内容会显示在浏览器的页面上。


定义视图函数

Django 项目中的应用下的 views.py 文件中定义如下格式函数即可

# -*- coding:utf-8 -*-
"""
@Author   :Hui
@Desc     :{book应用视图模块}
"""
from django.http import HttpResponse


# /book
def index(request):
    """图书首页"""
    return HttpResponse("图书首页")

复制代码

配置URL

查找视图的过程

请求者在浏览器地址栏中输入 URL ,请求到网站后,获取 URL 信息,然后与编写好的 URL配置 逐条匹配,如果匹配成功则调用对应的视图函数,如果所有的 URL配置都没有匹配成功,则返回 404 错误。

该如何配置呢?

我们只要在 Django 项目下的 urls.py 文件中添加自己 URL 匹配规则。

# -*- coding:utf-8 -*-
"""
@Author   :Hui
@Desc     :{BMSTest項目的url匹配模块}
"""
from book import views
from django.urls import path
from django.contrib import admin


urlpatterns = [
    path('admin/', admin.site.urls),
    path('book', views.index),
]

复制代码

urlpatterns url匹配列表中可以看见 path('admin/', admin.site.urls) 这行,这是 Django 项目默认

就有的匹配规则,代表访问 http://127.0.0.1:8000/admin/Django 会截取域名后面的地址进行匹配和处

理,截取后为 admin/,处理结果就是返回后台管理的登录页面。

path('book', views.index) 是我们自己加的匹配规则。意思就是当访问

http://127.0.0.1:8000/book 网址时, 截取后为 book , 然后在 urlpatterns 匹配列表中逐一匹配,

当匹配到 book 时符合匹配规则,让我们的 views.index 的视图函数进行处理。返回结果如下:

图书首页


但我们一般把匹配规则定义成如下格式:

# -*- coding:utf-8 -*-
"""
@Author   :Hui
@Desc     :{BMSTest項目的url匹配模块}
"""
from django.contrib import admin
from django.urls import path, re_path


urlpatterns = [
    re_path('admin/', admin.site.urls), # 后台管理
    re_path('^user/', include('user.urls')), # 用户模块
    re_path('^book/', include('book.urls')), # 图书模块
]

复制代码

应在每个应用中创建 urls.py url配置文件,然后让项目包含其中 include('book.urls')

# -*- coding:utf-8 -*-
"""
@Author   :Hui
@Desc     :{book应用的url匹配模块}
"""
from book import views
from django.urls import re_path


urlpatterns = [
    re_path('^index$', views.index),
]

复制代码

但这次访问图书首页的网址就改成了 http://127.0.0.1:8000/book/index 。先拿 book/index 跟项目的 urls.py 进行匹对,开头匹配到了 book/ 然后就去 book.urls ,book应用下的 urls.py进行匹对。匹配到了 index 就返回图书首页。

注意^ 表示匹配开头,$ 表示匹配结尾。 path 不支持正则表达式,如需支持正则需要在 django.urls 导入 re_path 。如想学正则,推荐 Python玩转正则表达式,看完这篇你就会了,介绍了一些常用表达式,和在线生成正则工具网站。


基于类的视图

基于类的视图提供了一种将视图实现为Python对象而非函数的替代方法。它们不能替代基于功能的视图,但是与基于功能的视图相比具有某些区别和优势:

  • 与特定HTTP方法(GET,POST等)相关的代码组织可以通过单独的方法而不是条件分支来解决。
  • 诸如 mixin(多重继承)之类的面向对象技术可用于将代码分解为可重用的组件。

定义类视图

还是在 Django 项目中的应用下的 views.py 文件中定义

首先导入 Django 的视图类

from django.views.generic import View
复制代码

然后让我们自己写的类继承 Django 的类视图 View

从本质上讲,基于类的视图使您可以使用不同的类实例方法来响应不同的 HTTP 请求方法,而不是使用单个视图函数中的有条件分支代码。

因此,视图函数中用于处理 HTTP请求的代码如下所示:

# -*- coding:utf-8 -*-
"""
@Author   :Hui
@Desc     :{book应用视图模块}
"""
from django.http import HttpResponse


# /book/index
def index(request):
    """图书首页"""
    if request.method == "GET":
        # 视图逻辑
        # ...
        return HttpResponse("GET请求 - 图书首页")

    elif request.method == "POST":
        # 视图逻辑
        # ...
        return HttpResponse("POST请求 - 图书首页")
    
复制代码

在基于类的视图中,这将变为:

# -*- coding:utf-8 -*-
"""
@Author   :Hui
@Desc     :{book应用视图模块}
"""
from django.views import View
from django.http import HttpResponse


# /book/info
class InfoView(View):
    """图书信息视图类"""

    def get(self, request):
        # 视图逻辑
        # ...
        return HttpResponse("GET请求 - 图书信息页")
    
    def post(self, request):
        # 视图逻辑
        # ...
        return HttpResponse("POST请求 - 图书信息页")
    
复制代码

配置URL

因为 DjangoURL解析器 希望将请求和关联的参数发送给可调用的函数而不是类,所以基于类的视图具有一个

as_view() 的类方法,该类方法返回一个函数,该请求可以在请求到达与关联模式匹配的 URL 时被调用。该

函数创建该类的实例,调用 setup() 以初始化其属性,然后调用其 dispatch() 方法。 dispatch 查看该请求

以确定它是否为 GET, POST 等,并将请求转发给匹配的方法(如果已定义),否则将其引发HttpResponseNotAllowed

因此我么配置URL是只要 类视图.as_view()即可,例如:

# -*- coding:utf-8 -*-
"""
@Author   :Hui
@Desc     :{book应用的url匹配模块}
"""
from book import views
from django.urls import re_path
from book.views import InfoView


urlpatterns = [
    re_path('^index$', views.index),
    re_path('^info$', InfoView.as_view())
]

复制代码

当在浏览器访问 http://127.0.0.1:8000/book/info 网址时, 截取后为 book/info , 然后在 urlpatterns 匹配列表中逐一匹配,当匹配到 ^info$ 时符合匹配规则,让我们的 InfoView.as_view() 的类视图进行处理。返回结果如下:

图书信息页 - GET


公众号

新建文件夹X

大自然用数百亿年创造出我们现实世界,而程序员用几百年创造出一个完全不同的虚拟世界。我们用键盘敲出一砖一瓦,用大脑构建一切。人们把1000视为权威,我们反其道行之,捍卫1024的地位。我们不是键盘侠,我们只是平凡世界中不凡的缔造者 。