django知识点二

Django视图和URL配置

一、MTV模式

1、概述

Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:

  • M 代表模型(Model):负责业务对象和数据库的关系映射(ORM)。 提供数据

  • T 代表模板 (Template):负责如何把页面展示给用户(html)渲染显示页面内容

  • V 代表视图(View):负责业务逻辑,并在适当时候调用Model和Template。

    1。通过request接收请求参数 2.处理业务逻辑(与数据库进行交互)3.返回相应函数

    每一个views函数都有一个对应函数url.path

Django中提供了View组件用来充当MVC中的C-controller。

创建过程:

  1. 通过pycharm创一个项目,数以选择解释器
  2. 创建一个app:目的还是为了松耦合
  3. 写一个视图函数-- 要一一对应url url.py文件中添加视图函数对应的url访问路劲
  4. 试图函数中可能会使用模块文件 redent/HttpResponse
  5. run project启动服务

2、view的主要职责

  • 接收请求
  • 调度Model,处理业务逻辑
  • 响应请求/转发Template(显示数据相关逻辑)

二、基本开发流程

1、创建App,定义view中的函数

在每个App的views.py中,定义一个hello函数

def hello(request):
    print("函数")

2、函数返回响应

每个view必须要有响应,即返回一个HttpResponse

from django.shortcuts import HttpResponse

def hello(request):
    return HttpResponse("<h1>view基本开发流程</h1>")
或者
    return render(request,'xxx.html')

3、定义访问路径

在urls.py中,为每个view定义访问路径

from django.urls import path
from view_app.views import hello   # 引入views模块中的hello

urlpatterns = [
    path("admin/",admin.site.urls),
    path("hello/",hello)            # 添加view中的配置
]

4、启动服务

django内置了一个供开发使用的 web-服务器,虽然不适合生产环境,但用户开发测试,特别便利。

python manage.py runserver  #默认ip和端口   localhost:8000

python manage.py runserver 0.0.0.0:8000 #修改默认的ip和端口
python manage.py runserver 192.168.0.3:8899

注意:修改了ip和port后,需要到settings.py中增加一个设置:ALLOWED_HOSTS = ["*"]

5、访问view

http://localhost:8000/hello/

htpp://本机ip:8000/hello/

三、URL配置

URL配置的本质是 URL 模式以及要为该 URL 模式调用的视图函数之间的映射表。

该配置用于告诉 Django,对于这个 URL 调用这段代码,对于那个 URL 调用那段代码。

例如,当用户访问xxx/hello时,调用视图函数hello(),这个视图函数存在于Python模块文件views.py中。

1、一般配置

from django.contrib import admin
from django.urls import path
from view_app.views import hello
urlpatterns = [
    path('admin/', admin.site.urls),
    path('hello/',xxx)              # http://localhost:8000/hello/
    path('hello/world/',xxx)        # http://localhost:8000/hello/world/
    path('hello/world/a/b/',xxx)    # http://localhost:8000/hello/world/a/b/
]

2、正则配置

from django.contrib import admin
from django.urls import path, re_path   # 引入 re_path 函数
from view_app.views import hello
urlpatterns = [
    path('admin/', admin.site.urls),
    re_path("hello/\\d{3}/",hello),   # localhost:8000/hello/三个整数/
    re_path(r"hello/\d{3}/",hello),   
    re_path(r'hello/\d{2,5}/\w+/',hello), # locahost:8000/hello/12415/dfasdf
                                    # locahost:8000/hello/12415/abc/def/
    re_path(r"hello/[a-d]*/$"),    # localhost:8000/abchello/abcaa/
    re_path(r"^hello/[a-d]*/$"),    # localhost:8000/hello/abcaa/
  ]

注意: 在使用正则时,^$ 可以保证精准匹配。 ^表示以什么开头, $ 表示以什么结尾。

3、URL技巧(path管理)

一个Project会有很多App,每个App会有很多View函数,如果都在一个urls.py中配置,则项目的管理和维护成本将急剧上升。

每个App不仅逻辑独立,也希望在url-pattern的配置上也相互隔离。

因此我们希望每个App都应该有一个独立的url-conf,在每个app下创建一个新的urls.py文件,然后在全局的urls.py中来包含各个app的url-conf。

  • 在App目录下,新建一个urls.py,并配置自己的url路径:
from django.contrib import admin
from django.urls import path,re_path
from view_app.views import hello

urlpatterns = [
    path('hello/',hello),
    re_path(r'hello/\d{2,5}/\w+/',hello),
]
  • 在全局urls.py中,使用include包含各个app的url-conf:
from django.contrib import admin
from django.urls import path,re_path,inlcude
from view_app.views import hello

urlpatterns = [
    path('admin/', admin.site.urls),
    path('view_app/',include("view_app.urls")),  # 导入外部的urls模块
    
    # view_app为 view_app.urls每一个path路径的前缀
]

# 如上的两个路径在访问时,都要加上全局路径中的view_app前缀
# http://localhost:8000/view_app/hello
# http://localhost:8000/view_app/hello/1243/abc

补充

​ 如果在一个app的众多path中,又有关系逻辑关联紧密的path,可以进一步管理:

from django.contrib import admin
from django.urls import path,re_path
from view_app.views import hello

urlpatterns = [
    path(...),
    ...
    path('user/vip',include([
        path('a/',view.helloa),   # http://.../view_app/user/vip/a/
        path('b/',view.hellob),   # http://.../view_app/user/vip/b/
        path('c/',view.helloc),   # http://.../view_app/user/vip/c/
    ])),
    ...
    path(...),
]

至此:View的url配置则有了管理方案:

  1. 每个App定义自己的urls.py,其中定义自己的url-conf。
  2. Project的全局urls.py中引入各个App的url-conf,并定义访问前缀,区分、隔离各个App
  3. App内部的url-conf可以根据逻辑进一步区分、隔离。

四、命名路径

1、基本使用

语法:

path("xxx/<参数名1>/<参数名2>/../", xxx)    # <参数名1> 此种路径可以匹配任何内容

示例:

path("hello/<name>/<age>/",hello)       # localhost:8000/hello/mr_lee/18/

def hello(request,name,age):
    ...

注意:有了命名路径,view的函数中必须有对应的接收参数。

2、命名路径转换器

非正则命名路径中可以使用转换器,以约束每个路径捕获到的数据的类型

  • int:接收整数
  • str:字符串(了解)
  • path:可以接收包含"/"的路径(了解)
  • slug:接收【数字、字母、下划线、中划线】四种字符(了解)

如果路径上的值不符合转换器类型,则访问不到对应的view函数(404页面)

path("hello/<int: age>/<str: name>/<slug:nick>",hello)

# http://localhost:8000/hello/18/Mrlee/ab_c12-def/
def hello(request,age,name,nick):
    print(age,name,nick)
    return HttpResponse('Done!')

3、正则命名路径

1、正则路径匹配且捕获数据

使用正则的“捕获组”的格式(regex)也可捕获到url路径中的数据。

即用括号包围的正则,就是一个捕获组,不仅匹配路径,还可以捕获到数据。

re_path("hello/(\d{3})/",hello1)                    # http://localhost:8000/hello/125/
re_path("hello2/(d{2,5})/(\w+)/",hello2)           # http://localhost:8000/hello2/43/abfa2_ad
re_path("hello3/([a-d]*)/",hello3)                 # http://localhost:8000/hello3/abcdef/
re_path("^hello4/([a-d]*)/$",hello4)               # http://localhost:8000/hello4/abc
                                                # 注意hello3与hello4的区别
def hello(request,a):
    print(a)
    return HttpResponse("Done!")

def hello2(request,a,b):
    print(a,b)
    return HttpResponse("Done!")

def hello3(request,a):
    print(a)
    return HttpResponse("Done!")

def hello4(request,a):
    print(a)
    return HttpResponse("Done!")
2、正则命名路径且捕获数据
re_path("hello/(?P<age>\d{3})/",hello1)             # http://localhost:8000/hello/125/
re_path("hello2/(?P<age>d{2,5})/(?P<name>\w+)/",hello2)  # http://localhost:8000/hello2/43/ab_f
re_path("hello3/(?P<nick>[a-d]*)/",hello3)         # http://localhost:8000/hello3/abcdef/
re_path("^hello4/(?P<nick>[a-d]*)/$",hello4)       # http://localhost:8000/hello4/abc
                                                # 注意hello3与hello4的区别
def hello(request,age):
    print(age)
    return HttpResponse("Done!")

def hello2(request,age,name):
    print(age,name
    return HttpResponse("Done!")

def hello3(request,nick)
    print(nick)
    return HttpResponse("Done!")

def hello4(request,nick)
    print(nick)
    return HttpResponse("Done!")

总结:捕获参数---获取url中的参数值

  1. 普通命名路径 xxx/<参数1>/<参数2>/。。。。->视图函数(request,参数名要对应)

五、请求处理

(1)用户发送请求 (2)服务器接收请求 (3)服务器处理请求

1、发送请求的方式

在Web中发送页面请求的方式一般有三种:

  • <a href="xxx"> 超链接
  • location.href="xxx" <buuton function>
  • <form action="xxx"> 表单
<html>
<head>
    <title>发送请求的三种方式</title>
    <script type="text/javascript"> 
        function myclick() {
            location.href = "http://localhost:8000/hello/123"
        }
    </script>
</head>
<body>
    <p><a href="http://e.dangdang.com/products/1900470914.html">打开</a></p>

<form action="http://e.dangdang.com/products/1900671721.html">
    <input type="submit" name="" value="提交">
</form>

<input type="button" name="" value="点我" onclick="myclick()">

</body>
</html>

2、接收请求参数

客户端(浏览器)访问服务器时,需要向服务器传递数据(请求参数),以让服务器可以区别处理。

比如:点击多个商品详情链接,会看到不同的商品的详情页面,服务器如何知道查询哪个商品的数据?

  • 方式一:接收路径中的参数
    • 命名路径
    • 正则路径
    • 正则命名路径
  • 方式二:常规的参数接收,通过request对象接收

3、超链接传参

超链接传参格式: url/?key=value&key2=value2

<a href="http://localhost:8000/hello5/?id=115&name=mr_lee">超链接传参</a>  # html超链接

path('hello5/',views.hello5)                        # url配置

def hello5(request):                                # view函数
    return HttpResponse("Done")

附:location.href传参与超链接传参类似。

4、表单传参

表单中的控件,name属性值为参数名,value属性值为参数值。

<form action="http://localhost:8000/hello6/" method="get">
    用户名:<input type="text" name="name" >
    密码:<input type="password" name="pwd">
    <input type="submit" name="" value="提交">
</form>

5、request接收请求参数

5.1 接收get请求参数
  • request.GET['参数名']
  • request.GET.get("参数名")
path('hello6/', views.hello6)

def hello6(request):
    print(request.GET['name'],request.GET['pwd'])
    return HttpResponse("Done")
5.2 接收post请求参数
  • request.POST['参数名']
  • request.POST.get("参数名")
<form action="http://localhost:8000/hello6/" method="post">
    {% csrf_token %}
    用户名:<input type="text" name="name" >
    密码:<input type="password" name="pwd">
    <input type="submit" name="" value="提交">
</form>
path('hello6/', views.hello6)

def hello6(request):
    print(request.POST['name'],request.POST['pwd'])
    return HttpResponse("Done")

注意:

  • GET['age'] 如果没有键则报错
  • GET.get('age') 如果没有键返回None

6、Get和Post请求区别

  • POST安全性好于GET,GET中的请求参数直接暴露于url上;传递密码等敏感数据时,不使用GET。
  • GET对数据长度有限制,URL 的最大长度是 2048 个字符,POST无限制。
  • HTTP的语义中GET请求用来查询数据,POST用来提交数据
  • GET只允许 ASCII 字符。POST可以传递各种数据,二进制也可以。
  • GET可以缓存,POST不能缓存

实用技巧:请求中有隐私数据(如密码) 或 有较多数据时不建议使用Get

实用场景:Get常用来做查询和删除请求,Post常用来做增加和更新请求

7、接收多值参数

  • 当请求参数中同一个key上有多个值,View中如何接收?

http://localhost:8000/test1/user/vip/a/?age=18&age=19&name=zhj

<form action="http://localhost:8000/hello7" method="GET">
    <input type="checkbox" name="hobby" value="football"/>足球
    <input type="checkbox" name="hobby" value="basketball"/>篮球
    <input type="checkbox" name="hobby" value="volleyball"/>排球
    <input type="submit" value="提交"/>
</form>

hobby有多个值,GET['hobby']得到的值是什么 ?

http://localhost:8000/hello7/?hobby=football&hobby=basketball&hobby=volleyball

def hello7(request):
    print(request.GET['hobby'])   #将只会得到最后一个值
    return HttpResponse("")
  • 使用GET.getlist("xxx")或POST.getlist("xxx")来接收多个相同key的值:
def hello7(request):
    print(request.GET.getlist('hobby'))
    return HttpResponse("")
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容