0%

Django(十一)视图详解:基本使用、登录实例、HttpReqeust对象、HttpResponse对象

详情请点阅读全文

一、视图(基于类的视图)

【参考】https://docs.djangoproject.com/zh-hans/3.0/topics/class-based-views/intro/

1)视图的功能

  1. 接收请求,进行处理,与M和T进行交互,返回应答。
  2. 返回html内容 HttpResponse,也可能重定向 redirect,还可以返回json数据。

    2)视图函数使用

    二、使用

    1. 定义视图函数

  • request参数必须有。
  • 是一个HttpRequest类型的对象。
  • 参数名可以变化,但不要更改。

    2. 配置url

  • 建立url和视图函数之间的对应关系。

2.2 url配置的过程

1) 在项目的urls文件中包含具体应用的urls文件,在具体应用的urls文件中包含具体url和视图的对应关系。
2) url配置项是定义在一个名叫urlpatterns的列表中,其中的每一个元素就是一个配置项,每一个配置项都调用url函数。

3. url匹配的过程

在这里插入图片描述
url:http://127.0.0.1:8000/aindex?a=1

1) 去除域名和后面的参数,剩下/aindex,再把前面的/去掉,剩下aindex
2) 拿aindex先到项目的url.py文件中进行从上到下的匹配,匹配成功之后执行后面对应的处理动作,就是把匹配成功的部分a字符去除,然后拿剩下的部分index到应用的urls.py文件中再进行从上到下的匹配。
3) 如果匹配成功则调用相应的视图产生内容返回给客户端。如果匹配失败则产生404错误。

4.错误视图

  1. 404:找不到页面,关闭调试模式之后,默认会显示一个标准的错误页面,如果要显示自定义的页面,则需要的templates目录下面自定义一个404.html文件。
    • a)url没有配置
    • b)url配置错误
  2. 500: 服务器端的错误。
    • a)视图出错,即views.py页面的对应函数内部出错会显示500错误。
  3. 网站开发完成需要关闭调试模式,在settings.py文件中:
    1
    2
    DEBUG=False
    ALLOWED_HOST=['*']
  4. 显示效果:Not Found
    The requested resource was not found on this server.
  5. 自定义错误页面:建立【templates/404.html】 即可,django会自动调用此页面,不需自己调用
    系统提供: 用于返回用户请求的path
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>404错误页面</title>
    </head>
    <body>
    <h1>页面找不到:--{{ request_path }}</h1>
    </body>
    </html>
  6. 自定义500错误页:建立【templates/500.html】 即可
1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>500错误页面</title>
</head>
<body>
<h1>服务器错误</h1>
</body>
</html>

5.捕获url参数

  • 进行url匹配时,把所需要的捕获的部分设置成一个正则表达式组,这样django框架就会自动把匹配成功后相应组的内容作为参数传递给视图函数。
    • 1)位置参数:参数名可以随意指定
    • 2)关键字参数:在位置参数的基础上给正则表达式组命名即可。
      1
      ?P<组名>
  • 关键字参数,视图中参数名必须和正则表达式组名一致.
  • 【实例】:
    https://blog.csdn.net/u010132177/article/details/103831173
    的第 二、通过url传参,访问书英雄详情

    1)加带参数的链接/templates/app1/book.html

    【1】通过href属性,把book的id做为参数传给详情页,进而查询对应英雄信息
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>书籍页面</title>
    </head>
    <body>
    本站的图书有:
    <ul>
    {% for book in books %}
    <!--【1】通过href属性,把book的id做为参数传给详情页,进而查询对应英雄信息-->
    <li><a href="/detail/{{book.id}}"> {{book.btitle}}</a>:{{book.bpub_date}}</li>
    {%empty%}
    暂时没有图书!!!
    {% endfor %}
    </ul>
    </body>
    </html>

    2)接收参数,渲染到模板app1/views.py

    【00】bookId为接收urls.py必须中指定的参数,来源页templates/app1/book.html
    【1】查询主键为url中传过来的参数Id。或写成:id=bookId
    【2】关联查询:查询对应书的所有英雄信息
    【3】把参数渲染到detail页面去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.shortcuts import render
from app1.models import BookInfo #【0】从模型下导入bookinfo数据模型

def index(request):
'''app1应用:首页'''
context={} #定义1个字典
context['hello']='hello world!!!' #向字典写一个键:值(hello:'hello world!!')
context['wa']='wawawawawahahahaha!'
context['list']=list(range(1,10)) #定义一个字典值为一个列表,list为把内容转换为列表
return render(request,'app1/index.html',context) #返回:把context渲染到app1/index.html的模板文件

def books(request):
'''app1应用:图书列表页'''
books=BookInfo.objects.all()#从数据库获取图书对象列表
return render(request,'app1/book.html',{'books':books})#把获取到的图书对象赋值给books键。【注意】键'books'必须要加引号

def detail(request,bookId):# 【00】bookId为接收urls.py必须中指定的参数,来源页templates/app1/book.html
'''app1应用:图书详情页,显示英雄信息'''
book=BookInfo.objects.get(pk=bookId) #【1】查询主键为url中传过来的参数Id。或写成:id=bookId
heros=book.heroinfo_set.all() #【2】关联查询:查询对应书的所有英雄信息
return render(request,'app1/detail.html',{'book':book,'heros':heros}) #【3】把参数渲染到detail页面去

3)app1/urls.py配置

【书详情页】通过url接收参数2种写法以下两种都可:
【1.关键字参数】参数用尖括号包起来<>path(r"detail/<int:bookId>",views.detail)(视图接收参数必须与此处保持一致,即 bookId)
【2.正则参数】参数必须要带括号re_path(r"^detail/(\d+)",views.detail)

1
2
3
4
5
6
7
8
9
10
11
from django.urls import path,re_path
from . import views

urlpatterns=[
path('app1/',views.index),
path('books/',views.books),

# 【书详情页】,通过url接收参数2种写法以下两种都可:
# path(r"detail/<int:bookId>",views.detail), #【尖括号】参数用尖括号包起来<>
re_path(r"^detail/(\d+)",views.detail), #【正则】参数必须要带括号
]

6.普通登录案例( HttpRequest和 HttpResponse对象的API django.http)

【参考】https://docs.djangoproject.com/zh-hans/3.0/ref/request-response/

0)知识点:views.py视图函数的request.POST、request.GET

  1. request.POST 保存的是post方式提交的参数 QueryDict
  2. request.GET 保存是get方式提交的参数
  3. 它俩的类型 print(request.POST/GET) 返回 QueryDict类型
  4. QueryDict的传参数方式、调用方式1、调用方式2、
  5. 调用不存在的值、传入类似列表值、类似列表值调用。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    >>> from django.http.request import QueryDict #引入模块

    >>> q=QueryDict('a=1&b=2&c=3') #传参形式
    >>> q['a'] #调用方式1
    '1'
    >>> q.get('a') #调用方式2
    '1'
    >>> q.get('d') #调用不存在的值,什么都不返回
    >>> q.get('d','default') #设置调用不存在的值,返回一个默认的值
    'default'

    >>> q['d'] #调用方式1调用不存在的值,会直接报错,因此,使用调用方式一get会比较好

    '''
    Traceback (most recent call last):
    File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-p
    ackages\django\utils\datastructures.py", line 76, in __getitem__
    list_ = super().__getitem__(key)
    KeyError: 'd'

    During handling of the above exception, another exception occurred:

    Traceback (most recent call last):
    File "<console>", line 1, in <module>
    File "C:\Users\Administrator\AppData\Local\Programs\Python\Python37\lib\site-p
    ackages\django\utils\datastructures.py", line 78, in __getitem__
    raise MultiValueDictKeyError(key)
    django.utils.datastructures.MultiValueDictKeyError: 'd'
    '''

    >>> q2=QueryDict('a=1&a=2&a=3') #传入类似列表值、及调用
    >>> q2['a']
    '3'
    >>> q2.get('a')
    '3'
    >>> q2.getlist('a')
    ['1', '2', '3']

1)显示出登录页面

参考:https://docs.djangoproject.com/zh-hans/3.0/topics/forms/

1) 设计url,通过浏览器访问 http://127.0.0.1:8000/login 时显示登录页面。
2) 设计url对应的视图函数login。
3) 编写模板文件login.html。

url | 视图 | 模板文件
|—|—|—|
/login | login | login.html

2)登录校验功能

1) 设计url,点击登录页的登录按钮发起请求http://127.0.0.1:8000/login_check时进行登录校验。
2) 设计url对应的视图函数login_check:
- 接收表单提交过来的数据。
- 进行登录校验,若用户名密码正确则跳转到登录成功页。若失败在跳转到登录页面。
3) 登录成功后跳转到首页。

url | 视图| 模板文件
|—|—|—|
/login_check | login_check | 无

第1步,app1/views.py编写登陆函数、校验函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from django.shortcuts import render,redirect #引入重定向简写模块

def login(request):
'''登录页'''
return render(request,'app1/login.html')

def login_check(request):
'''登录校验'''
username=request.POST.get('username') #对应模板的input的name选项
password=request.POST.get('password')
if username=='jim' and password=='123':
return redirect('/books')
else:
return redirect('/login')

第2步,登录页面模板templates/app1/login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
POST:提交的参数请求头。数据安全性要求比较高的时候使用post.<br/>
GET:提交的参数在url中。<br/>
<form method="post" action="/login_check"> <!--action提交页面-->
用户名:<input type="text" name="username" value="{{ username }}"><br/>
密码:<input type="password" name="password"><br/>
<input type="submit" value="登录">
</form>
</body>
</html>

第3步,app1/urls.py设置

【登录页】
【登录检测】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.urls import path,re_path
from . import views

urlpatterns=[
path('login/',views.login),#【登录页】
path('login_check',views.login_check),#【登录检测】

path('app1/',views.index),
path('books/',views.books),

# 书详情页,通过url接收参数2种写法以下两种都可:
# path(r"detail/<int:bookId>",views.detail), #参数用尖括号包起来<>
re_path(r"^detail/(\d+)",views.detail), #参数必须要带括号

path('addInfo/',views.addInfo), #添加三国书

path(r'delete/<int:bid>',views.deleteInfo), #删除对应图书

path(r'areas/',views.areas), #展示对应省市区信息
]

第4步,把project1/settings.py

把MIDDLEWARE 的 csrf注释掉,否则将无法实现登录。

1
2
3
4
5
6
7
8
9
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

第5步,启动项目进入项目目录

1
py manage.py runserver

效果 http://127.0.0.1:8000/login/

输入jim 123即跳转到 books/页面,否则跳转回登录页面。
在这里插入图片描述

扩展:获取请求的方式是get还是post,/app1/views.py

1
print(request.method)

HttpReqeust对象

  • 服务器接收到http协议的请求后,会根据报文创建HttpRequest对象,这个对象不需要我们创建,直接使用服务器构造好的对象就可以。视图的第一个参数必须是HttpRequest对象,在django.http模块中定义了HttpRequest对象的API。

属性

下面除非特别说明,属性都是只读的。

  • path:一个字符串,表示请求的页面的完整路径,不包含域名和参数部分。
  • method:一个字符串,表示请求使用的HTTP方法,常用值包括:’GET’、’POST’。
    在浏览器中给出地址发出请求采用get方式,如超链接。
    在浏览器中点击表单的提交按钮发起请求,如果表单的method设置为post则为post请求。
  • encoding:一个字符串,表示提交的数据的编码方式。
    如果为None则表示使用浏览器的默认设置,一般为utf-8。
    这个属性是可写的,可以通过修改它来修改访问表单数据使用的编码,接下来对属性的任何访问将使用新的encoding值。
  • GET:QueryDict类型对象,类似于字典,包含get请求方式的所有参数。
  • POST:QueryDict类型对象,类似于字典,包含post请求方式的所有参数。
  • FILES:一个类似于字典的对象,包含所有的上传文件。
  • COOKIES:一个标准的Python字典,包含所有的cookie,键和值都为字符串。
  • session:一个既可读又可写的类似于字典的对象,表示当前的会话,只有当Django 启用会话的支持时才可用,详细内容见”状态保持”。

运行服务器,在浏览器中浏览首页,可以在浏览器“开发者工具”中看到请求信息如下图:
在这里插入图片描述

示例

  • 接下来演示属性path、method、encoding,对于GET、POST、FILES、COOKIES、session后面会有详细讲解。

  • path、encoding

1)打开booktest/views.py文件,代码如下:

1
2
3
def index(request):
str='%s,%s'%(request.path,request.encoding)
return render(request, 'booktest/index.html', {'str':str})

2)在templates/booktest/下创建index.html文件,代码如下:

1
2
3
4
5
6
7
8
9
10
<html>
<head>
<title>首页</title>
</head>
<body>
1. request对象的path,encoding属性:<br/>
{{ str }}
<br/>
</body>
</html>

2)打开浏览器请求,运行效果如下图:
在这里插入图片描述
3)以chrome浏览器为例,设置编码如下图,默认为utf-8编码。
在这里插入图片描述

method

1)打开booktest/views.py文件,编写视图method_show,代码如下:

1
2
def method_show(request):
return HttpResponse(request.method)

2)打开booktest/urls.py文件,新增配置如下:

1
url(r'^method_show/$', views.method_show),

3)修改templates/booktest/下创建index.html文件,添加代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
<title>首页</title>
</head>
<body>
...
...
2.request对象的method属性:<br/>
<a href='/method_show/'>get方式</a><br/>
<form method="post" action="/method_show/">
<input type="submit" value="post方式">
</form>
<br/>
</body>
</html>

4)打开浏览器,输入如下网址:
http://127.0.0.1:8000/
5)浏览效果如下图:
在这里插入图片描述
6)点击链接,转到method_show,浏览效果如下图:
在这里插入图片描述
7) 回到method_test页面,点击按钮,转到method_post,浏览效果如下图,报错了。
在这里插入图片描述
9)回到浏览器中刷新,浏览效果如下图,点击“继续”按钮。
在这里插入图片描述
10)最终浏览效果如下图:

在这里插入图片描述

HttpResponse对象

视图在接收请求并处理后,必须返回HttpResponse对象或子对象。在django.http模块中定义了HttpResponse对象的API。HttpRequest对象由Django创建,HttpResponse对象由开发人员创建。

运行服务器,在浏览器中浏览首页,可以在浏览器“开发者工具”中看到响应信息如下图:
在这里插入图片描述

属性

  • content:表示返回的内容。
  • charset:表示response采用的编码字符集,默认为utf-8。
  • status_code:返回的HTTP响应状态码。
  • content-type:指定返回数据的的MIME类型,默认为’text/html’。

方法

  • _init_:创建HttpResponse对象后完成返回内容的初始化。
  • set_cookie:设置Cookie信息。
  • set_cookie(key, value=’’, max_age=None, expires=None)
  • cookie是网站以键值对格式存储在浏览器中的一段纯文本信息,用于实现用户跟踪。
  • max_age是一个整数,表示在指定秒数后过期。
  • expires是一个datetime或timedelta对象,会话将在这个指定的日期/时间过期。
  • max_age与expires二选一。
    如果不指定过期时间,在关闭浏览器时cookie会过期。
  • delete_cookie(key):删除指定的key的Cookie,如果key不存在则什么也不发生。
  • write:向响应体中写数据。

实例

直接返回数据

1)打开booktest/views.py文件,定义视图index2如下:

1
2
3
def index2(request):
str='<h1>hello world</h1>'
return HttpResponse(str)

2)打开booktest/urls.py文件,配置url。

1
url(r'^index2/$',views.index2),

3)运行服务器,在浏览器中打开如下网址。

1
http://127.0.0.1:8000/index2/

在这里插入图片描述
如果使用这种方式构造一个漂亮丰富的页面,对于开发人员真是会发疯,于是就有了下面的方式:

调用模板

可以将html、css、js定义到一个html文件中,然后由视图来调用。

1)打开booktest/views.py文件,定义视图index3如下:

1
2
3
4
5
6
7
8
9
from django.template import RequestContext, loader
...
def index3(request):
#加载模板
t1=loader.get_template('booktest/index3.html')
#构造上下文
context=RequestContext(request,{'h1':'hello'})
#使用上下文渲染模板,生成字符串后返回响应对象
return HttpResponse(t1.render(context))

2)打开booktest/urls.py文件,配置url。

1
url(r'^index3/$',views.index3),

3)在templates/booktest/目录下创建index3.html,代码如下:

1
2
3
4
5
6
7
8
<html>
<head>
<title>使用模板</title>
</head>
<body>
<h1>{{h1}}</h1>
</body>
</html>

4)运行服务器,在浏览器中打开如下网址。

http://127.0.0.1:8000/index3/
运行效果如下图:
在这里插入图片描述

调用模板简写函数render

每次调用模板时都要执行加载、上下文、渲染三个步骤,为了简化操作,Django定义了render()函数封装了以上三个步骤的代码,定义在django.shortcuts模块中。

1)打开booktest/views.py文件,定义视图index3如下:

1
2
3
4
from django.shortcuts import render
...
def index3(request):
return render(request, 'booktest/index3.html', {'h1': 'hello'})

是不是用render()函数调用模板比上面简单多了?