Django5视图定义与使用
8919字约30分钟
2025-02-16
视图(Views)是 Django的 MTV架构模式的V部分,主要负责处理用户请求和生成相应的响应内容,然后 在页面或其他类型文档中显示。
Django的MTV分别代表:
Model(模型):业务对象与数据库的对象(ORM)
Template(模版):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
Django5设置视图响应状态
客户端请求后端服务,在view.py视图层方法最终return 返回视图响应。Python内置提供了响应类型, 来实现不同的返回不同的http状态码;
响应类型 | 解释说明 |
---|---|
HttpResponse('Hello world'") | 状态码200,请求已成功被服务器接收 |
HttpResponseRedirect('/') | 状态码302,重定向首页地址 |
HttpResponsePermanentRedirect('/') | 状态码301,永久重定向首页地址 |
HttpResponseBadRequest("'400') | 状态码400,访问的页面不存在或请求错误 |
HttpResponseNotFound('404") | 状态码404,网页不存在或网页的URL失效 |
HttpResponseForbidden('403') | 状态码403,没有访问权限 |
HttpResponseNotAllowed('405') | 状态码405,不允许使用该请求方式 |
HttpResponseServerError('500'") | 状态码500,服务器内容错误 |
JsonResponse( {'foo' : 'bar'}) | 默认状态码200,响应内容为JSON数据 |
StreamingHttpResponse() | 默认状态码200,响应内容以流式输出 |
下面我们举几个例子来实操下视图响应状态应用;
举例一:HttpResponse
修改helloWorld的views.py的index函数:
def index(request):
html = "<font color='red'>学Python,上www.python222.com</font>"
return HttpResponse(html, status=200)
请求测试,状态码200,返回网页信息。status=200不写的话默认也是200.
举例二:HttpResponseNotFound 404
def index(request):
return HttpResponseNotFound()
请求测试,状态码404。
举例三:JsonResponse 响应json数据
def index(request):
return JsonResponse({'foo': 'bar'})
请求测试,状态码200,返回json格式数据。
我们第一个实例用到的是HttpResponse,简单网页我们直接可以响应到页面,但是假如是复杂网页,就 会增加视图函数的代码量。所以我们引入模版,通过django提供的render方法渲染数据到模版,然后再 响应到页面。
def index(request):
return render(request, 'index.html')
这个是我们前面的的HelloWorld代码,我们ctrl点进去render方法,看下源码:
经过模版渲染后得到content网页内容,依然返回的是HttpResponse对象。
render方法定义:
def render(request, template_name, context=None, content_type=None, status=None,using=None):
request和template_name是必须的参数。其他参数可选。
- request:浏览器向服务器发送的请求对象,包含用户信息、请求内容和请求方式等。
- template_name:设置模板文件名,用于生成网页内容。
- context:对模板上下文(模板变量)赋值,以字典格式表示,默认情况下是一个空字典。
- content_type:响应内容的数据格式,一般情况下使用默认值即可。
- status: HTTP状态码,默认为200.
- using:设置模板引擎,用于解析模板文件,生成网页内容。
我们再写一个带字典参数的render渲染模版实例:
views.py改写下:
def index(request):
content_value = {"msg": '学Python,上www.python222.com'}
return render(request, 'index.html', context=content_value)
模版代码改写下,模版里取值语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
模版取值: {{ msg }}
</body>
</html>
请求测试:
Django5设置重定向响应
Django重定向我们前面讲过一种urls.py里使用RedirectView实现
path('redirectTo', RedirectView.as_view(url="index/"))
这种方便书写简单,但是不灵活,我们实际开发,为了能否实现业务上的判断,来进行业务重定向跳 转,还是需要用redirect方法。
重定向的状态码分为301和302,前者是永久性跳转的,后者是临时跳转的,两者的区别在于搜索引擎的 网页抓取。301重定向是永久的重定向,搜索引擎在抓取新内容的同时会将旧的网址替换为重定向之后 的网址。302跳转是暂时的跳转,搜索引擎会抓取新内容而保留旧的网址。因为服务器返回302代码,所 以搜索引擎认为新的网址只是暂时的。
Django内置提供了重定向类HttpResponseRedirect和HttpResponsePermanentRedirect分别代表 HTTP状态码302和301
我们通过一个实例来测试下重定向
我们static下面新建一个新页面new.html
改写helleWorld里得index方法:
def index(request):
return redirect("/static/new.html")
我们测试下:请求 http://127.0.0.1:8000/index/ 302跳转到了new.html页面 (最好用谷歌浏览 器得无痕浏览,这样没有缓存干扰测试)
我们加上 permanent=True 参数;
def index(request):
return redirect("/static/new.html", permanent=True)
再测试下,就变成301永久跳转了。
我们点进去看下redirect方法得源码实现:
def redirect(to, *args, permanent=False, **kwargs):
"""
Return an HttpResponseRedirect to the appropriate URL for the arguments
passed.
The arguments could be:
* A model: the model's `get_absolute_url()` function will be called.
* A view name, possibly with arguments: `urls.reverse()` will be used
to reverse-resolve the name.
* A URL, which will be used as-is for the redirect location.
Issues a temporary redirect by default; pass permanent=True to issue a
permanent redirect.
"""
redirect_class = (
HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
)
return redirect_class(resolve_url(to, *args, **kwargs))
第一个跳转参数支持模型,视图路由名称,还有最常用得url地址;第二个参数就是是否永久跳转,默认 Flase;
redirect_class通过permanent判断,true返回HttpResponsePermanentRedirect,false返回 HttpResponseRedirect;
Django5二进制文件下载响应
响应内容除了返回网页信息外,还可以实现文件下载功能,是网站常用的功能之一。
Django提供三种方式实现文件下载功能,分别是HttpResponse、StreamingHttpResponse和 FileResponse,三者的说明如下:
- HttpResponse是所有响应过程的核心类,它的底层功能类是HttpResponseBase。
- StreamingHttpResponse是在 HttpResponseBase的基础上进行继承与重写的,它实现流式响应 输出(流式响应输出是使用Python的迭代器将数据进行分段处理并传输的),适用于大规模数据响 应和文件传输响应。
- FileResponse是在StreamingHttpResponse 的基础上进行继承与重写的,它实现文件的流式响应 输出,只适用于文件传输响应。
我们通过实例来看下如何应用:
我们准备一个文件,这里我们用一个exe二进制文件。放D盘根目录。
views.py里写方法实现方法:
# 定义文件路径
file_path = "D:\\360zip_setup.exe"
def download_file1(request):
file = open(file_path, 'rb') # 打开文件
response = HttpResponse(file) # 创建HttpResponse对象
response['Content_Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename=file1.exe'
return response
def download_file2(request):
file = open(file_path, 'rb') # 打开文件
response = StreamingHttpResponse(file) # 创建StreamingHttpResponse对象
response['Content_Type'] = 'application/octet-stream
response['Content-Disposition'] = 'attachment;filename=file2.exe'
return response
def download_file3(request):
file = open(file_path, 'rb') # 打开文件
response = FileResponse(file) # 创建FileResponse对象
response['Content_Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename=file3.exe'
return response
urls.py里定义下映射:
path('download1', helloWorld.views.download_file1),
path('download2', helloWorld.views.download_file2),
path('download3', helloWorld.views.download_file3)
为了方便测试,我们static目录下新建一个download.html静态文件:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>下载测试</title>
</head>
<body>
<a href="/download1">下载测试一:HttpResponse</a><br>
<a href="/download2">下载测试二:StreamingHttpResponse</a><br>
<a href="/download3">下载测试三:FileResponse</a>
</body>
</html>
页面输入: http://127.0.0.1:8000/static/download.html 测试:
分别点击下载测试
Http请求&HttpRequest请求类
超文本传输协议(Hypertext Transfer Protocol,HTTP)是一个简单的请求-响应协议,它通常运行在 TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
当在浏览器上访问某个网址时,其实质是向网站发送一个HTTP请求,HTTP请求分为8种请求方式,每种 请求方式的说明如下:
请求方式 | 说明 |
---|---|
OPTIONS | 返回服务器针对特定资源所支持的请求方法 |
GET | 向特定资源发出请求(访问网页) |
POST | 向指定资源提交数据处理请求(提交表单、上传文件) |
PUT | 向指定资源位置上传数据内容 |
DELETE | 请求服务器删除request-URL所标示的资源 |
HEAD | 与GET请求类似,返回的响应中没有具体内容,用于获取报头 |
TRACE | 回复和显示服务器收到的请求,用于测试和诊断 |
CONNECT | HTTP/1.1协议中能够将连接改为管道方式的代理服务器 |
在上述的HTTP请求方式里,最基本的是GET请求和POST 请求,网站开发者关心的也只有GET请求和 POST请求。GET请求和 POST请求是可以设置请求参数的,两者的设置方式如下:
- GET请求的请求参数是在路由地址后添加“?”和参数内容,参数内容以key=value 形式表示,等号前 面的是参数名,后面的是参数值,如果涉及多个参数,每个参数之间就使用“&”隔开,如 127.0.0.1:8000/?name=python222&pw=123456。
- POST请求的请求参数一般以表单的形式传递,常见的表单使用HTML的 form标签,并且form标签 的method 属性设为POST.
在Django5中,Http请求信息都被封装到了HttpRequest类中。
HttpRequest类的常用属性如下:
- COOKIE:获取客户端(浏览器)的Cookie信息,以字典形式表示,并且键值对都是字符串类型。
- FILES: django.http.request.QueryDict对象,包含所有的文件上传信息。
- GET:获取GET请求的请求参数,它是django.http.request.QueryDict对象,操作起来类似于字典。
- POST:获取POST请求的请求参数,它是django.http.request.QueryDict对象,操作起来类似于字典。
- META:获取客户端(浏览器)的请求头信息,以字典形式存储。
- method:获取当前请求的请求方式(GET请求或POST请求).
- path:获取当前请求的路由地址。
- session:一个类似于字典的对象,用来操作服务器的会话信息,可临时存放用户信息。
- user:当 Django启用AuthenticationMiddleware中间件时才可用。它的值是内置数据模型User的 对象,表示当前登录的用户。如果用户当前没有登录,那么user将设为 django.contrib.auth.models.AnonymousUser的一个实例。
HttpRequest类常用方法如下:
- is_secure():是否是采用HTTPS协议。
- get_host():获取服务器的域名。如果在访问的时候设有端口,就会加上端口号,如 127.0.0.1:8000。
- get_full path():返回路由地址。如果该请求为GET请求并且设有请求参数,返回路由地址就会将请 求参数返回,如/?name=python222&pw=123456。
我们搞个实例来测试下吧:
先views.py里定义两个方法,分别测试get和post:
def get_test(request):
"""
get请求测试
:param request:
:return:
"""
print(request.method) # 请求方式
# 常用属性
print(request.content_type)
print(request.content_params)
print(request.COOKIES)
print(request.scheme)
# 常用方法
print(request.is_secure())
print(request.get_host())
print(request.get_full_path())
print(request.GET.get("name"))
print(request.GET.get("pwd"))
print(request.GET.get("aaa", "666"))
return HttpResponse("http get ok")
def post_test(request):
"""
post请求测试
:param request:
:return:
"""
print(request.method) # 请求方式
print(request.POST.get("name"))
print(request.POST.get("pwd"))
print(request.POST.get("aaa", "666"))
return HttpResponse("http post ok")
urls.py里定义下映射:
path('get', helloWorld.views.get_test),
path('post', helloWorld.views.post_test)
模版里新建http.html,这里我们不能用静态页面,需要一个csrf安全机制token 需要后端server来提 供,所以只能用模版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/get?name=python222&pwd=123456" target="_blank">http get请求测试</a><br>
<br>
<form action="/post" method="post">
{% csrf_token %}
name:<input type="text" name="name"><br>
pwd:<input type="text" name="pwd">
<input type="submit" value="提交"></input>
</form>
</body>
</html>
请求index跳转到http.html
def index(request):
return render(request, 'http.html')
浏览器输入 http://127.0.0.1:8000/index/ 测试:
点击get链接地址:
后台输出:
GET
text/plain
{}
{'csrftoken': 'GDgfE2kvXwRYS6WMejaYNE9ij9KPodHi'}
http
False
127.0.0.1:8000
/get?name=python222&pwd=123456
python222
123456
666
请求处理完毕,将返回到页面
[20/Feb/2024 17:09:52] "GET /get?name=python222&pwd=123456 HTTP/1.1" 200 11
在post表单测试:
后台输出:
POST
python222
123456
666
会话管理(Cookies&Session)
HTTP是一种无状态协议,每次客户端访问web页面时,客户端打开一个单独的浏览器窗口连接到web服 务器,由于服务器不会自动保存之前客户端请求的相关信息,所有无法识别一个HTTP请求是否为第一次 访问。这就引进了web客户端和服务器端之间的会话,这就是会话管理。
常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在 服务器端记录信息确定用户身份。
一、关于Cookie
cookie是某些网站为了辨别用户身份,进行Session跟踪而储存在用户本地终端上的数据(通常经过加 密),由用户客户端计算机暂时或永久保存的信息。
Cookie定义了一些HTTP请求头和HTTP响应头,通过这些HTTP头信息使服务器可以与客户进行状态交 互。
客户端请求服务器后,如果服务器需要记录用户状态,服务器会在响应信息中包含一个Set-Cookie的响 应头,客户端会根据这个响应头存储Cookie信息。再次请求服务器时,客户端会在请求信息中包含一个 Cookie请求头,而服务器会根据这个请求头进行用户身份、状态等较验。
二、关于session
Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务 器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是 Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包 含了一个session标识,称为session id,如果已包含一个session id则说明以前已经为此客户端创建过 session,服务器就按照session id把这个session检索出来使用(如果检索不到,可能会新建一个),如 果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的 session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个 session id将被在本次响应中返回给客户端保存。
三、Session和Cookie的区别
- 数据存储位置:cookie 数据存放在客户的浏览器上,session 数据放在服务器上。
- 安全性:cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应 当使用session。
- 服务器性能:session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能, 考虑到减轻服务器性 能方面,应当使用cookie。
- 数据大小:单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- 信息重要程度:可以考虑将用户信息等重要信息存放为session,其他信息如果需要保留,可以放在 cookie中。
四、Cookies&Session再Django中使用实例
获取 cookie
request.COOKIES['key']
request.COOKIES.get('key')
这俩个方法可以获取指定键名的cookie
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
default: 默认值
salt: 加密盐
max_age: 后台控制过期时间,默认是秒数
expires: 专门针对IE浏览器设置超时时间
设置 cookie
# 获取HttpResponse对象
# rep = HttpResponse(...)
rep = render(request, ...)
# 设置 cookie
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
参数
key, 键
value='', 值
max_age=None, 超时时间
expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)
path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
domain=None, Cookie生效的域名
secure=False, https传输
httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
删除 cookie
# 获取HttpResponse对象
# rep = HttpResponse(...)
rep = render(request, ...)
# 删除 cookie
rep.delete_cookie(key)
此方法会删除用户浏览器上之前设置的cookie值
Django 操作 session
1. 获取、设置、删除Session中数据
request.session['k1'] # 没有值会报错
下面通过一个具体Django事例来深入体验下Django项目里的Cookie&Session操作
views.py里定义两个方法,分别是登录页面跳转,以及登录逻辑处理
request.session.get('k1',None) # 可以获取多组
request.session['k1'] = 123 # 可以设置多组
request.session.setdefault('k1',123) # 存在则不设置
del request.session['k1']
2. 所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
request.session.iterkeys()
request.session.itervalues()
request.session.iteritems()
3. 会话session的key
request.session.session_key
4. 将所有Session失效日期小于当前日期的数据删除
request.session.clear_expired()
5. 检查会话session的key在数据库中是否存在
request.session.exists("session_key")
6. 删除当前会话的所有Session数据
request.session.delete() # 只删客户端
7. 删除当前的会话数据并删除会话的Cookie。
request.session.flush() # 服务端、客户端都删
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它
8. 设置会话Session和Cookie的超时时间
'django默认的session失效时间是14天'
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
下面通过一个具体Django事例来深入体验下Django项目里的Cookie&Session操作
views.py里定义两个方法,分别是登录页面跳转,以及登录逻辑处理
def to_login(request):
"""
跳转登录页面
:param request:
:return:
"""
urls.py里定义映射:
templates下新建login.html和main.html
login.html
return render(request, 'login.html')
def login(request):
"""
登录
:param request:
:return:
"""
user_name = request.POST.get("user_name")
pwd = request.POST.get("pwd")
if user_name == 'python222' and pwd == '123456':
request.session['currentUserName'] = user_name # session中存一个用户名
print('session获取', request.session['currentUserName'])
response = render(request, 'main.html') # 获取HttpResponse
response.set_cookie("remember_me", True) # 设置cookie
return response
else:
content_value = {"error_info": '用户名或者密码错误!'}
return render(request, 'login.html', context=content_value)
urls.py里定义映射:
path('toLogin/', helloWorld.views.to_login),
path('login', helloWorld.views.login)
templates下新建login.html和main.html
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="/login" method="post">
{% csrf_token %}
<table>
<tr>
<th>用户登录</th>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" name="user_name"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="pwd"></td>
</tr>
<tr>
<td>
<input type="submit" value="提交">
</td>
</tr>
<tr>
<td colspan="2"><font color="red">{{ error_info }}</font></td>
</tr>
</table>
</form>
</body>
</html>
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>主页面</title>
</head>
<body>
欢迎:{{ request.session.currentUserName }}
</body>
</html>
测试运行,浏览器输入: http://127.0.0.1:8000/toLogin/
转发到login.html
我们先输入一个错误的用户名和密码:
携带错误信息参数,转发到登录页面,页面提示错误信息。
我们在输入一个正确的用户名和密码:,则转发到main.html主页面。
同时服务器返回set-cookies信息,包括内置的sessionid以及我们自己设置的remember_me。
Django 中的 Session 配置
1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为
None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
# 其他公用设置项:
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
Django5文件上传实现
文件上传功能是网站开发或者业务系统常见的功能之一,比如上传图片(用户头像或文章配图)和导入 文件(压缩包,视频,音乐)。无论上传的文件是什么格式的,其上传原理都是将文件以二进制的数据格 式读取并写入网站或者业务系统指定的目录里。
我们通过一个实例来深入体验学习下文件上传:
首先templates下新建upload.html ,前端上传文件模版页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
</head>
<body>
<form action="/upload" enctype="multipart/form-data" method="post">
{% csrf_token %}
<input type="file" name="myfile"><br><br>
<input type="submit" value="上传文件">
</form>
</body>
</html>
views.py里定义to_upload和upload两个方法,分别是跳转文件页面,和文件上传处理
def to_upload(request):
"""
跳转文件上传页面
:param request:
:return:
"""
return render(request, 'upload.html')
def upload(request):
"""
文件上传
:param request:
:return:
"""
# 获取上传的文件,如果没有文件,就默认为None
myFile = request.FILES.get("myfile", None)
if myFile:
# 打开特定的文件进行二进制的写操作
f = open(os.path.join("D:\\myFile", myFile.name), "wb+")
# 分块写入文件
for chunk in myFile.chunks():
f.write(chunk)
f.close()
return HttpResponse("文件上传成功!")
else:
return HttpResponse("没发现文件!")
最后urls.py里,定义下映射:
path('toUpload/', helloWorld.views.to_upload),
path('upload', helloWorld.views.upload)
运行测试:浏览器输入 http://127.0.0.1:8000/toUpload/ ,进入文件上传页面:
测试两个文件,一个压缩包,一个图片,选择文件,点击上传文件,则上传到指定目录:
文件对象myFile提供一下属性来获取文件信息:
- myFile.name:获取上传文件的文件名,包含文件后缀名。
- myFile.size:获取上传文件的文件大小。
- myFile.content_type:获取文件类型,通过后续名判断文件类型。
从文件对象myFile获取文件内容,Django提供了以下读取方式,每种方式说明如下。
- myFile.read():从文件对象里读取整个文件上传的数据,这个方法只适合小文件。
- myFile.chunks():按流式响应方式读取文件,在for 循环中进行迭代,将大文件分块写入服务器所指 定的保存位置。
- myFile.multiple_chunks():判断文件对象的文件大小,返回True或者False,当文件大于2.5MB(默认 值为2.5MB)时,该方法返回True,否则返回False。因此,可以根据该方法来选择选用read方法 读取还是采用chunks方法。
Django5列表视图ListView
为了实现快速开发,Django提供了视图类功能,封装了视图开发常用的代码,这种基于类实现的响应与 请求称为CBV ( Class Base Views),我们先介绍列表视图ListView,该视图类可以将数据库表的数据以 列表的形式显示到页面,常用于数据的查询和展示。
首先为了得到数据库数据,我们先定义模型,来映射数据库表;
models.py里定义StudentInfo类:
from django.db import models
# Create your models here.
class StudentInfo(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
age = models.IntegerField()
class Meta:
db_table = "t_student"
然后我们执行: python manage.py makemigrations 生成数据库迁移文件
所谓的迁移文件, 是类似模型类的迁移类,主要是描述了数据表结构的类文件;
再执行: python manage.py migrate 执行迁移文件,同步到数据库中
注意:生成的表名默认为:app名_定义的表名,可通过db_table 指明数据库表名。
我们会看到 数据库t_student自动生成了:
我们输入一些测试数据:
insert into t_student VALUES(null,'张三1',20);
insert into t_student VALUES(null,'张三2',21);
insert into t_student VALUES(null,'张三3',22);
insert into t_student VALUES(null,'张三4',23);
insert into t_student VALUES(null,'张三5',24);
insert into t_student VALUES(null,'张三6',25);
insert into t_student VALUES(null,'张三7',26);
insert into t_student VALUES(null,'张三8',27);
insert into t_student VALUES(null,'张三9',28);
insert into t_student VALUES(null,'张三10',29);
insert into t_student VALUES(null,'张三11',30);
insert into t_student VALUES(null,'张三12',31);
要使用 ListView,需要继承它并设置一些属性。以下属性是最常用的:
- model :指定要使用的模型。
- template_name :指定要使用的模板名称。
- context_object_name :指定上下文变量名称,默认为 object_list。
- paginate_by :指定分页大小。
- extra_context :设置模型外的数据
在views.py里,我们可以定义List类:
class List(ListView):
# 设置模版文件
template_name = 'student/list.html'
# 设置模型外的数据
extra_context = {'title': '学生信息列表'}
# 查询结果集
queryset = StudentInfo.objects.all()
# 每页展示5条数据
paginate_by = 5
# 设置上下文对象名称
context_object_name = 'student_list'
除了设置属性之外,还可以重写 ListView 中的方法以进行自定义。以下是一些常见的方法:
- get_queryset() :返回要在视图中使用的查询集合。这里可以对查询集合进行筛选、排序等操 作。
- get_context_data() :返回要在模板上下文中使用的变量。这里可以添加额外的变量,如表单、 过滤器等。
urls.py里,我们定义映射:
path('student/list', helloWorld.views.List.as_view())
在模版页面,Django 给我们提供了分页的功能: Paginator 和 Page 类都是用来做分页的。
# Paginator常用属性和方法
1.`count`: 总共有多少条数据。
2.`num_pages`: 总共有多少页。
3.`page_range`:页面的区间。比如有三页,那么就是```range``(``1``,``4``)`。
# Page常用属性和方法:
1.`has_next`: 是否还有下一页。
2.`has_previous`: 是否还有上一页。
3.`next_page_number`: 下一页的页码。
4.`previous_page_number`: 上一页的页码。
5.`number`: 当前页。
6.`start_index`: 当前页的第一条数据的索引值。
7.`end_index`: 当前页的最后一条数据的索引值。
我们在templates下新建student目录,再新建list.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<table border="1">
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
</tr>
{% for student in student_list %}
<tr>
<td>{{ student.id }}</td>
<td>{{ student.name }}</td>
<td>{{ student.age }}</td>
</tr>
{% endfor %}
</table>
<br>
{% if is_paginated %}
{% if page_obj.has_previous %}
<a href="/student/list?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
{% for current in paginator.page_range %}
{% if current == page_obj.number %}
<a href="/student/list?page={{ current }}"><b><font color="blue">{{ current }}</font></b></a>
{% else %}
<a href="/student/list?page={{ current }}">{{ current }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="/student/list?page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
{% endif %}
</body>
</html>
测试,浏览器输入: http://127.0.0.1:8000/student/list
点击下一页:
运用ListView列表视图开发,是不是非常容易,方便。
Django5详细视图DetailView
DetailView多用于展示某一个具体数据对象的详细信息的页面。
使用DetailView,你只需要指定要使用的模型和对象的唯一标识符,并可以自定义其他一些属性,例如 模型名称、模板名称、上下文数据等。
以下是DetailView的一些常见属性和方法:
- model:指定要使用的模型。
- queryset:指定要使用的查询集,用于获取对象。如果未指定,则将使用模型的默认查询集。
- pk_url_kwarg:指定URL中用于获取对象的唯一标识符的参数名称,默认为’pk’。
- context_object_name:指定将对象传递给模板时的上下文变量名称,默认为’model’。
- template_name:指定要使用的模板的名称。
- get_object(queryset=None):获取要展示的对象。可以重写这个方法来自定义获取对象的逻辑。
- get_context_data(kwargs):返回要传递给模板的上下文数据。你可以重写这个方法来自定义上下 文数据。
- get():处理GET请求的方法,根据配置的对象获取规则执行对象获取和展示逻辑。
- dispatch(request, *args, **kwargs):处理请求的入口方法,根据请求的不同方法(GET、POST 等)执行相应的处理逻辑。
通过继承DetailView,并根据自己的需求重写这些方法,你可以创建自定义的展示单个对象详细信息的 视图,并实现你想要的功能。
总之,DetailView是Django框架中的一个便捷的通用视图,用于展示单个对象的详细信息,并提供了一 些有用的属性和方法来简化对象展示逻辑。
通过重新设置model属性来指定需要获取的Model类,默认对象名称为object,也可以通过重新设置 context_object_name属性来更改这个名字。
下面我们通过实例来体验下吧:
views.py里新建Detail,继承DetailView
class Detail(DetailView):
# 设置模版文件
template_name = 'student/detail.html'
# 设置模型外的数据
extra_context = {'title': '学生信息详情'}
# 设置查询模型
model = StudentInfo
# 设置上下文对象名称
context_object_name = 'student'
# 指定URL中用于获取对象的唯一标识符的参数名称,默认为’pk’。
# pk_url_kwarg = 'id'
templates下的student目录下新建detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
编号:{{ student.id }}<br/>
姓名:{{ student.name }}<br/>
年龄:{{ student.age }}
</body>
</html>
urls.py里加一个映射:
path('student/<int:pk>', helloWorld.views.Detail.as_view()),
list.html里,加一个操作项-查看详情:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<table border="1">
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>操作</th>
</tr>
{% for student in student_list %}
<tr>
<td>{{ student.id }}</td>
<td>{{ student.name }}</td>
<td>{{ student.age }}</td>
<td>
<a href="/student/{{ student.id }}">查看详情</a>
</td>
</tr>
{% endfor %}
</table>
<br>
{% if is_paginated %}
{% if page_obj.has_previous %}
<a href="/student/list?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
{% for current in paginator.page_range %}
{% if current == page_obj.number %}
<a href="/student/list?page={{ current }}"><b><font color="blue">{{ current }}</font></b></a>
{% else %}
<a href="/student/list?page={{ current }}">{{ current }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="/student/list?page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
{% endif %}
</body>
</html>
运行测试,浏览器输入: http://127.0.0.1:8000/student/list ,点击"查看详情"
即可查询出学生详情;
Django5新增视图CreateView
视图类CreateView是对模型新增数据的视图类,它是在表单视图类FormView 的基础上加以封装的。简 单来说,就是在视图类FormView的基础上加入数据新增的功能。
所有涉及到表单视图的功能开发,都需要定义form表单类:
我们新建forms.py,里面新建StudentForm
from django import forms
from django.forms import ModelForm
from helloWorld.models import StudentInfo
# 定义学生form表单
class StudentForm(ModelForm):
# 配置中心
class Meta:
model = StudentInfo # 导入model
# fields = '__all__' # 代表所有字段
fields = ['name', 'age'] # 指定字段
widgets = { # 定义控件
'name': forms.TextInput(attrs={'id': 'name', 'class':'inputClass'}),
'age': forms.NumberInput(attrs={'id': 'age'})
}
labels = { # 指定标签
'name': '姓名',
'age': '年龄'
}
views.py里新建Create类,继承CreateView
class Create(CreateView):
# 设置模版文件
template_name = 'student/create.html'
# 设置模型外的数据
extra_context = {'title': '学生信息添加'}
# 指定form
form_class = StudentForm
# 执行成功后跳转地址
success_url = '/student/list'
student目录下新建create.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<style>
.inputClass {
width: 200px;
}
</style>
</head>
<body>
<h3>{{ title }}</h3>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="确定">
</form>
</body>
</html>
urls.py里加一个映射:
path('student/create', helloWorld.views.Create.as_view()),
list.html页面,加一个新增学生链接
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<a href="/student/create">新增学生</a>
<table border="1">
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>操作</th>
</tr>
{% for student in student_list %}
<tr>
<td>{{ student.id }}</td>
<td>{{ student.name }}</td>
<td>{{ student.age }}</td>
<td>
<a href="/student/{{ student.id }}">查看详情</a>
</td>
</tr>
{% endfor %}
</table>
<br>
{% if is_paginated %}
{% if page_obj.has_previous %}
<a href="/student/list?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
{% for current in paginator.page_range %}
{% if current == page_obj.number %}
<a href="/student/list?page={{ current }}"><b><font color="blue">{{ current }}</font></b></a>
{% else %}
<a href="/student/list?page={{ current }}">{{ current }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="/student/list?page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
{% endif %}
</body>
</html>
测试,浏览器输入: http://127.0.0.1:8000/student/list
点击“新增学生“链接
输入表单信息
点击确定,则跳转到学生信息列表页面
Django5修改视图UpdateView
视图类UpdateView是在视图类FormView和视图类DetailView的基础上实现的,它首先使用视图类 DetailView的功能(功能核心类是SingleObjectMixin),通过路由变量查询数据表某条数据并显示在网页 上,然后在视图类FormView的基础上,通过表单方式实现数据修改。
views.py里新建Update类:
class Update(UpdateView):
# 设置模版文件
template_name = 'student/update.html'
# 设置模型外的数据
extra_context = {'title': '学生信息编辑'}
# 设置查询模型
model = StudentInfo
# 指定form
form_class = StudentForm
# 执行成功后跳转地址
success_url = '/student/list'
student下新建update.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<style>
.inputClass {
width: 200px;
}
</style>
</head>
<body>
<h3>{{ title }}</h3>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="确定">
</form>
</body>
</html>
urls.py里加一个映射:
path('student/update/<int:pk>', helloWorld.views.Update.as_view()),
list.html里加一个
<a href="/student/update/{{ student.id }}">修改</a>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<a href="/student/create">新增学生</a>
<table border="1">
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>操作</th>
</tr>
{% for student in student_list %}
<tr>
<td>{{ student.id }}</td>
<td>{{ student.name }}</td>
<td>{{ student.age }}</td>
<td>
<a href="/student/{{ student.id }}">查看详情</a>
<a href="/student/update/{{ student.id }}">修改</a>
</td>
</tr>
{% endfor %}
</table>
<br>
{% if is_paginated %}
{% if page_obj.has_previous %}
<a href="/student/list?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
{% for current in paginator.page_range %}
{% if current == page_obj.number %}
<a href="/student/list?page={{ current }}"><b><font color="blue">{{ current }}</font></b></a>
{% else %}
<a href="/student/list?page={{ current }}">{{ current }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="/student/list?page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
{% endif %}
</body>
</html>
运行测试:浏览器输入 http://127.0.0.1:8000/student/list
点击修改,进入修改页面,我们发现,django自动帮我获取了数据,并且填充到了表单
我们修改,数据:
点击确定提交,则django给我们做了数据库修改操作,然后跳到列表页面。是不是非常的方便。
Django5删除视图DeleteView
视图类DeleteView的使用方法与视图类UpdateView类似,视图类DeleteView只能删除单条数据,路由 变量为模型主键提供查询范围,因为模型主键具有唯一性,所以通过主键查询能精准到某条数据。查询 出来的数据通过POST 请求实现数据删除。
views.py里面,我们新建Delete类,继承DeleteView
class Delete(DeleteView):
# 设置模版文件
template_name = 'student/delete.html'
# 设置模型外的数据
extra_context = {'title': '学生信息删除'}
# 设置上下文对象名称
context_object_name = 'student'
# 设置查询模型
model = StudentInfo
# 执行成功后跳转地址
success_url = '/student/list'
urls.py里加下映射:
path('student/delete/<int:pk>', helloWorld.views.Delete.as_view()),
student下新建delete.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<form method="post">
{% csrf_token %}
您确定更要删除 id:{{ student.id }} name:{{ student.name }} age:{{ student.age }} 的记录吗 ?
<input type="submit" value="确定">
</form>
</body>
</html>
list.hml加下
<a href="/student/delete/{{ student.id }}">删除</a>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h3>{{ title }}</h3>
<a href="/student/create">新增学生</a>
<table border="1">
<tr>
<th>编号</th>
<th>姓名</th>
<th>年龄</th>
<th>操作</th>
</tr>
{% for student in student_list %}
<tr>
<td>{{ student.id }}</td>
<td>{{ student.name }}</td>
<td>{{ student.age }}</td>
<td>
<a href="/student/{{ student.id }}">查看详情</a>
<a href="/student/update/{{ student.id }}">修改</a>
<a href="/student/delete/{{ student.id }}">删除</a>
</td>
</tr>
{% endfor %}
</table>
<br>
{% if is_paginated %}
{% if page_obj.has_previous %}
<a href="/student/list?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
{% for current in paginator.page_range %}
{% if current == page_obj.number %}
<a href="/student/list?page={{ current }}"><b><font color="blue">{{ current }}</font></b></a>
{% else %}
<a href="/student/list?page={{ current }}">{{ current }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a href="/student/list?page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
{% endif %}
</body>
</html>
运行测试:浏览器输入: http://127.0.0.1:8000/student/list
点击删除,进入删除确定页面:
点击 确定,django帮我删除数据后,转发到列表页面: