9-Django框架之视图层
HttpResponse
HttpResponse
是 Django 中用于创建 HTTP 响应对象的类,它允许你构建并返回服务器对客户端请求的数据和状态。当需要直接返回纯文本数据(如 JSON 格式的数据)或者 HTML 页面时,可以使用
HttpResponse
。
正常返回纯文本
返回一个字典类型时
返回一个HTML标签
返回json数据
render
render
函数是 Django 的模板渲染机制的一部分,通常与模板引擎(如 Django 的默认模板引擎 - Jinja2 或者其它支持的模板引擎)一起使用。当你想要返回带有动态内容的 HTML 页面时,可以使用
render
函数将请求的数据与预定义的 HTML 模板结合起来:
redirect
redirect
函数用于实现网页间的重定向,即将用户从当前 URL 引导向另一个 URL。它不返回任何内容,而是引发一个 HTTP Redirection 错误,迫使客户端发送一个新的请求到指定地址:
注意:不需要加request! 不然会和我一样在奇怪的地方卡住很久 QAQ
JsonResponse
参数如果是一个字典或者列表类型,前端Ajax接收的就直接是一个对象了
先看一个案例,直接返回一个字典过去,数据直接把字典的键拼接到一起了,值直接没有了
用json试一下
用JsonResponse试一下
from django.http import JsonResponse
解决方案,添加一个参数,json_dumps_params={'ensure_ascii': False}就可以解决了,可以查看对应的源码,连引号也成中文了。
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
if safe and not isinstance(data, dict):
raise TypeError(
'In order to allow non-dict objects to be serialized set the '
'safe parameter to False.'
)
if json_dumps_params is None:
json_dumps_params = {}
kwargs.setdefault('content_type', 'application/json')
# 注意这个位置
data = json.dumps(data, cls=encoder, **json_dumps_params)
super().__init__(content=data, **kwargs)
尝试返回一个字典
JsonResponse在序列化字典以外的数据格式时,会有一个安全设置,我们将参数safe=False即可正常返回数据
form表单文件上传下载
<form action="" method="post" enctype="multipart/form-data"></form>
form表单想要上传文件类型的数据
method 参数必须改为post
enctype 参数必须指定成 form-data 类型
POST请求数据
数据获取request.FILES
无法直接获取到数据,可以通过request.FILES去获取,得到的看起来像字符串,其实并不是字符串
if request.method == 'POST':
file_obj = request.FILES
print(file_obj) # <MultiValueDict: {'一张图片': [<InMemoryUploadedFile: 三个女孩.jpg (image/jpeg)>]}>
写入文件,遍历chunks()(官方建议)
def file_test(request):
if request.method == 'POST':
file_obj = request.FILES.get('一张图片')
with open(rf'E:\djangoProject\TestDemo\t1\static\t1\img\{file_obj}', 'wb') as file:
for line in file_obj.chunks():
# 差不多逐行写入
file.write(line)
return render(request, 't1/index.html')
总结request对象方法
request.method:获取HTTP请求方法,可以是'GET'、'POST'、'PUT'、'DELETE'等。
request.GET: 获取通过 URL 查询参数传递的数据。通
- 通过get取值
request.GET <QueryDict: {'name': ['你好!'], 'password': ['123131'], 'hobby': ['music']}>
request.POST: 获取通过 POST 方法传递的表单数据,包含了请求中通过文件上传组件发送的所有文件,您可以使用文件的名字作为键来访问单个文件,例如
request.FILES['file']
。
- 通过get取值
request.GET <QueryDict: {'name': ['你好!'], 'password': ['123131'], 'hobby': ['music']}>
request.FILES: 获取通过 POST 方法上传的文件数据。
<MultiValueDict: {'一张图片': [<InMemoryUploadedFile: 三个女孩.jpg (image/jpeg)>]}>
request.COOKIES: 获取请求中的 cookie 数据。
request.session: 获取或设置与当前会话相关的数据。
request.path: 获取请求的路径部分。
request.path /t1/show_data
equest.path_info:只能获取路由地址,无法获取查询字符串
通常情况下,您可以使用
request.path
来获取丢弃域名后的路径,而使用request.path_info
来获取原始的、未解析的路径。这在某些情况下非常有用,例如当您需要对URL进行一些自定义操作或路由处理时。/t1/show_data
request.get_full_path(): 获取完整的地址,即能获取到路由地址又能获取到完整的路由地址后面的参数
/t1/show_data/?name=%E4%BD%A0%E5%A5%BD%EF%BC%81&password=123131&hobby=music
request.method: 获取请求的 HTTP 方法类型(GET、POST 等)。
request.META: 包含有关请求的元数据,如请求头信息等。
FBV与CBV引入
视图函数既可以是函数也可以是类
我们之前写过的都是基于函数的view,就叫FBV。
还可以把view写成基于类的。
FBV
FBV: function based view
就是平常在views.py中写的函数
# 一个简单的FBV
def tpl(request):
data_list = []
for index in range(10):
url = "https://api.vvhan.com/api/love?type=json"
data = requests.get(url, headers={'User-Agent': UserAgent().random}).json()
data_list.append(data)
return render(request, 'app1/tpl.html', {'data': data_list})
CBV
CBV: class based view
就是平常在views.py中写的类
Python是一个面向对象的编程语言,如果只用函数来开发,有很多面向对象的优点就错失了(继承、封装、多态)。所以Django在后来加入了Class-Based-View。可以让我们用类写View。这样做的优点主要下面两种:
- 提高了代码的复用性,可以使用面向对象的技术,比如Mixin(多继承)
- 可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
from django.views import View
from django.shortcuts import render, reverse, redirect, HttpResponse
from . import models
# 注册视图
class Register(View):
def get(self, request, *args, **kwargs):
return render(request, 'app1/register.html')
def post(self, request, *args, **kwargs):
# 获取用户名
username = request.POST.get('username')
# 查询数据库,如果数据库存在让用户继续注册,并打印错误信息在页面
flag = models.UserInfo.objects.filter(username=username).filter()
if flag:
error = f'对不起,用户{username}已存在!'
return render(request, 'app1/register.html', {'error': error})
# 如果用户不存在,则把数据存入数据库
password = request.POST.get('password')
models.UserInfo.objects.create(username=username, password=password)
# 跳转到登录视图
login_url = reverse('app1:Login')
return redirect(login_url)
# 登录视图
class Login(View):
def get(self, request, *args, **kwargs):
return render(request, 'app1/login.html')
def post(self, request, *args, **kwargs):
# 登录视图直接查询数据库,验证是否登录过
username = request.POST.get('username')
password = request.POST.get('password')
flag = models.UserInfo.objects.filter(username=username, password=password).filter()
if flag:
return HttpResponse('恭喜,登录成功!')
# 路由层
from . import views
from django.urls import path, re_path
app_name = "app1"
urlpatterns = [
# 这里使用需要添加括号,剖析源码可以得知,得到的是内存地址,并不是真正的执
path('register/', views.Register.as_view()),
path('login/', views.Login.as_view(), name='Login')
]
<!-- register.html -->
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册界面</title>
<link rel="stylesheet" href="{% static 'app1/css/bootstrap-theme.css' %}">
<link rel="stylesheet" href="{% static 'app1/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'app1/css/style.css' %}">
<script src="{% static 'app1/js/sweetalert.min.js' %}"></script>
</head>
<body>
<form method="post">
{% csrf_token %}
<p>输入账号:<input type="text" id="username" name="username" placeholder="此处输入账号" required>
<span class="error-msg"> {{ error }}</span>
</p>
<p>输入密码:<input type="password" name="password" placeholder="此处输入密码" required></p>
<button type="submit" id="submit-msg" class="btn btn-success">提交</button>
<button type="reset" class="btn btn-success">重置</button>
</form>
</body>
</html>
{# login.html #}
{% include 'app1/register.html' %}
- 选择使用 FBV 还是 CBV 取决于具体的需求和个人偏好。
- FBV 相对简单直观,适合编写简单的视图逻辑;
- 而 CBV 可以通过继承和重写类来实现代码复用和可扩展性,适用于复杂的视图处理场景。
- 在实际开发中,可以根据需求选择适合的方式来编写视图处理函数或类。
给视图添加装饰器
给FBV添加装饰器
FBV同普通函数一样,略过不谈
给CBV添加装饰器
方法1,正常使用函数的语法糖装饰器即可
import time
from functools import wraps
def timer(func):
@wraps(func)
def inner(*args, **kwargs):
t1 = time.time()
res = func(*args, **kwargs)
print('总耗时', time.time()-t1) # 总耗时 2.0102639198303223
return res
return inner
class UseLess(View):
@timer
def get(self, request):
time.sleep(2)
return HttpResponse('ok')
方法2,通过databases模块
import time
from dataclasses import dataclass
@dataclass
class Timer:
f: callable
def __call__(self, *args, **kwargs):
t1 = time.time()
res = self.f(self, *args, **kwargs)
print('总耗时', time.time()-t1) # 总耗时 2.0062646865844727
return res
class UseLess(View):
@Timer
def get(self, request):
time.sleep(2)
return HttpResponse('ok')
方法3,使用django自带的装饰器method_decorator
import time
from functools import wraps
# 使用前先导入
from django.utils.decorators import method_decorator
# 函数装饰器不需要做任何修改
def timer(func):
@wraps(func)
def inner(*args, **kwargs):
t1 = time.time()
res = func(*args, **kwargs)
print('总耗时', time.time()-t1) # 总耗时 2.00778865814209
return res
return inner
class UseLess(View):
# 注意这里
@method_decorator(timer)
def get(self, request):
time.sleep(2)
return HttpResponse('ok')
方法4,重写dispatch (了解即可)
使用CBV时要注意,请求过来后会先执行dispatch()这个方法
如果需要批量对具体的请求处理方法,如get,post等做一些操作的时候,这里我们可以手动改写dispatch方法,这个dispatch方法就和在FBV上加装饰器的效果一样。
class Login(View):
def dispatch(self, request, *args, **kwargs):
print('before')
obj = super(Login,self).dispatch(request, *args, **kwargs)
print('after')
return obj
def get(self,request):
return render(request,'login.html')
def post(self,request):
print(request.POST.get('user'))
return HttpResponse('Login.post')
本文作者:小满三岁啦
本文链接:https://www.cnblogs.com/ccsvip/p/18090670
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。