当前位置: 首页 > news >正文

Django视图进阶:快捷函数、装饰器与请求响应

        在上一篇文章中欧,我们学习了Django视图与路由的基础流程 —— 通过路由映射请求到视图,用视图函数处理简单逻辑并返回响应。但在实际开发中,我们还需要更高效的工具(如快捷函数)、更灵活的功能扩展(如视图装饰器),以及处理复杂场景(如JSON响应。文件上传)。本篇文章将聚焦这些进阶能力,带你提示Django视图开发的效率与灵活性

一、快捷函数:简化视图开发

Django的 django.shortcuts 模块提供了一组快捷函数,封装了视图开发中常用的重复逻辑(如渲染模板、查询数据、重定向),让你用更少的代码实现更多功能

1.1 render():渲染模版并返回响应

最常用的快捷函数,用于将模板与上下文数据结合,生成 HttpResponse 对象,无需手动创建 HttpResponse ,也无需指定模版路径(Django 会自动在templates 目录下查找)

语法:

render(request, template_name, context=None, content_type=None, status=None, using=None)

①request:Http请求对象(必须传)                             ②template_name:模版文件名(必须传)

③context:传递给模版的上下文字典(键为模版变量名,值为数据)        ④status:Http状态码

举例:

# myapp/views.py
from django.shortcuts import render
from .models import Articledef article_detail(request, pk):"""用render()渲染文章详情模板"""article = Article.objects.get(pk=pk)# 上下文字典:模板中可通过{{ article.title }}访问数据context = {'article': article,'author': article.author.username,  # 关联数据'is_favorite': request.user.is_authenticated  # 业务逻辑判断}# 渲染模板并返回响应(无需手动创建HttpResponse)return render(request, 'article_detail.html', context)

在模版中使用上下文:

<!-- article_detail.html -->
<h1>{{ article.title }}</h1>
<p>作者:{{ author }}</p>
{% if is_favorite %}<button>添加收藏</button>
{% endif %}
<div>{{ article.content }}</div>

1.2 redirect():重定向到其他URL

用于实现页面跳转,支持三种跳转场景:

① 跳转到命名路由(推荐使用)        ② 跳转到带参数的命名路由

③ 跳转到外部URL (如 http://example.com)

语法:

redirect(to, *args, permanent=False, **kwargs)

① to:目标URL(可以是命名路由名、路径字符串、外部 URL)       

② permanent:是否为永久重定向(True对应301状态码,False对应302,默认为False)

③ args/kwargs:传递给命名路由的参数

举例:

# myapp/views.py
from django.shortcuts import redirect, render, get_object_or_404
from django.urls import reverse
from .models import Articledef add_article(request):"""添加文章后重定向到文章详情页"""if request.method == 'POST':title = request.POST.get('title')content = request.POST.get('content')# 创建文章article = Article.objects.create(title=title, content=content)# 场景1:跳转到带参数的命名路由(推荐)return redirect('article_detail', pk=article.pk)  # 等价于 reverse('article_detail', args=[article.pk])# GET请求:显示添加文章表单return render(request, 'add_article.html')def redirect_to_home(request):"""跳转到首页(命名路由为'home')"""# 场景2:跳转到无参数的命名路由return redirect('home')def redirect_to_external(request):"""跳转到外部URL(如Django官网)"""# 场景3:跳转到外部链接return redirect('https://www.djangoproject.com/')

1.3 get_object_or_404():查询对象或返回404

查询单个对象时,若对象不存在,自动抛出 Http404异常(返回404页面),无需手动写 try-except捕获DoesNotExist 异常,代码简洁明了

语法:

get_object_or_404(klass, *args, **kwargs)

① klass:模型类(如Article)或查询集

② *args/**kwargs:查询条件

举例:

# 优化前:手动try-except
def article_detail_old(request, pk):try:article = Article.objects.get(pk=pk)except Article.DoesNotExist:raise Http404('文章不存在')return render(request, 'article_detail.html', {'article': article})# 优化后:用get_object_or_404()
from django.shortcuts import get_object_or_404def article_detail(request, pk):# 若找不到pk=pk的Article,自动返回404article = get_object_or_404(Article, pk=pk, is_published=True)  # 可加额外条件(如仅查询已发布文章)return render(request, 'article_detail.html', {'article': article})

1.4 get_list_or_404():查询列表或返回404

与 get_object_or_404()类似,但用于查询多个对象(查询集):若查询集为空,自动返回 404 页面;若有数据,返回查询集

语法:

get_list_or_404(klass, *args, **kwargs)

参数与 get_object_or_404()一致,返回值为查询集(而非单个对象)

举例:

from django.shortcuts import get_list_or_404def published_articles(request):"""查询已发布的文章列表,为空则返回404"""# 若没有is_published=True的文章,自动返回404articles = get_list_or_404(Article, is_published=True)return render(request, 'article_list.html', {'articles': articles})

二、视图装饰器:增强视图功能

视图装饰器是 Python 装饰器在 Django 视图中的应用,用于在不修改视图函数代码的前提下,为其添加额外功能(如限制 HTTP 方法、要求登录、缓存页面)。Django 提供了多个内置装饰器,也支持自定义

2.1 限制 HTTP 方法:控制请求类型

最常用的装饰器之一,用于限制视图仅接受特定的 HTTP 方法(如仅 GET、仅 POST),避免非法请求(如用 DELETE 方法访问列表页)

常用装饰器:

① @require_http_methods(['方法1', '方法2']):仅允许指定的 HTTP 方法

② @require_GET:仅允许 GET 方法(等价于@require_http_methods(['GET']));

③ @require_POST:仅允许 POST 方法(等价于@require_http_methods(['POST']));

④ @require_safe:仅允许 GET 和 HEAD 方法(安全方法,不修改数据)

举例:

# myapp/views.py
from django.views.decorators.http import require_http_methods, require_GET, require_POST
from django.shortcuts import render, redirect
from .models import Article# 1. 仅允许GET和POST方法
@require_http_methods(['GET', 'POST'])
def edit_article(request, pk):article = get_object_or_404(Article, pk=pk)if request.method == 'GET':# GET:显示编辑表单return render(request, 'edit_article.html', {'article': article})elif request.method == 'POST':# POST:处理表单提交article.title = request.POST.get('title')article.content = request.POST.get('content')article.save()return redirect('article_detail', pk=article.pk)# 2. 仅允许GET方法(显示文章列表)
@require_GET
def article_list(request):articles = Article.objects.all()return render(request, 'article_list.html', {'articles': articles})# 3. 仅允许POST方法(处理表单提交)
@require_POST
def delete_article(request, pk):article = get_object_or_404(Article, pk=pk)article.delete()return redirect('article_list')

效果:当使用不允许的方法访问时(如用 PUT 访问edit_article),Django 会自动返回405 Method Not Allowed响应

2.2 @gzip_page:压缩响应内容

用于对视图返回的响应内容进行 Gzip 压缩,减少网络传输数据量,提升页面加载速度(尤其适合大文本响应,如 HTML、JSON)

举例:

from django.views.decorators.gzip import gzip_page
from django.http import HttpResponse# 压缩响应内容
@gzip_page
def large_response(request):"""返回大文本响应,自动压缩"""# 模拟大文本(如长文章、大量数据)large_text = 'Django 视图装饰器...' * 1000return HttpResponse(large_text)

注意:仅在生产环境生效,开发环境(DEBUG=True)下可能不压缩

2.3 其他常用装饰器

(1)@login_required:要求用户登录

限制视图仅允许已登录用户访问,未登录用户会被重定向到登录页面(需在settings.py中配置LOGIN_URL

举例:

from django.contrib.auth.decorators import login_required
from django.shortcuts import render# 要求登录才能访问个人资料页
@login_required(login_url='/login/')  # 未登录时重定向到/login/
def user_profile(request):# request.user 为当前登录用户(已通过认证)return render(request, 'profile.html', {'user': request.user})

配置LOGIN_URL(可选,默认/accounts/login/):

# settings.py
LOGIN_URL = '/login/'  # 未登录用户的重定向地址

(2)@permission_required:要求用户有特定权限

限制视图仅允许具有指定权限的用户访问(如 “修改文章” 权限),未授权用户返回 403 页面

from django.contrib.auth.decorators import permission_required
from django.shortcuts import get_object_or_404, render
from .models import Article# 要求用户有"修改文章"权限(权限名格式:app_label.permission_name)
@permission_required('myapp.change_article', raise_exception=True)
def edit_article(request, pk):"""仅允许有修改权限的用户编辑文章"""article = get_object_or_404(Article, pk=pk)# 编辑逻辑...return render(request, 'edit_article.html', {'article': article})

① 'myapp.change_article':权限名,myapp是应用名,change_article是 Django 自动为Article模型生成的权限(默认有add/change/delete/view四种权限);

② raise_exception=True:未授权时直接返回 403,而非重定向

(3)@csrf_exempt:豁免 CSRF 保护

Django 默认对 POST 请求进行 CSRF 保护(需在表单中添加{% csrf_token %}),但对于 API 接口(如接收外部服务的 POST 请求),可能需要豁免 CSRF 验证

from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
import json# 豁免CSRF保护(仅用于API接口,谨慎使用)
@csrf_exempt
def api_receive_data(request):if request.method == 'POST':# 接收外部POST数据(无需CSRF令牌)data = json.loads(request.body)# 处理数据...return JsonResponse({'status': 'success', 'data': data})return JsonResponse({'status': 'error'}, status=400)

警告:仅在确认安全的场景下使用(如内部 API),公开接口需用其他认证方式(如 Token)

(4)@cache_page:缓存页面响应

缓存视图返回的响应,指定时间内重复请求会直接返回缓存结果,无需重新执行视图逻辑(提升高频访问页面的性能)

from django.views.decorators.cache import cache_page
from django.shortcuts import render# 缓存15分钟(单位:秒)
@cache_page(60 * 15)
def popular_articles(request):"""热门文章列表:15分钟内仅执行一次视图逻辑"""# 耗时查询(如排序、过滤大量数据)articles = Article.objects.all().order_by('-views')[:10]return render(request, 'popular_articles.html', {'articles': articles})

注意:缓存基于 URL,不同 URL(如/popular/?page=1/popular/?page=2)会分别缓存

三、内置视图:直接复用的“现成功能”

Django 提供了一些内置视图,封装了常见场景的完整逻辑(如处理静态文件、错误页面),无需自己编写视图函数,直接配置路由即可使用

3.1 serve:开发环境处理媒体文件

在开发环境中,Django 默认不处理用户上传的媒体文件(如头像、附件),需用django.views.static.serve视图手动配置媒体文件的访问路径

配置步骤

# 项目主 urls.py
from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.views.static import serve
from django.conf.urls.static import staticurlpatterns = [path('admin/', admin.site.urls),# 配置媒体文件访问:/media/xxx/ → 映射到settings.MEDIA_ROOT/xxxpath('media/<path:path>/', serve, {'document_root': settings.MEDIA_ROOT}),
]# (可选)开发环境静态文件配置(Django 1.11+ 可省略,自动处理)
if settings.DEBUG:urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

配置MEDIA_ROOTMEDIA_URL

# settings.py
import os# 媒体文件存储路径(用户上传的文件会保存在这里)
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# 媒体文件访问URL前缀(如 /media/avatar.jpg)
MEDIA_URL = '/media/'

注意:仅用于开发环境,生产环境需用 Nginx/Apache 处理媒体文件

3.2 内置错误视图

Django 提供了 4 个内置错误视图,对应 400、403、404、500 错误,可直接复用或自定义模板

错误类型内置视图作用
400 Bad Requestdjango.views.defaults.bad_request请求参数错误
403 Permission Denieddjango.views.defaults.permission_denied权限不足
404 Page Not Founddjango.views.defaults.page_not_found页面不存在
500 Internal Server Errordjango.views.defaults.server_error服务器内部错误

自定义内置错误视图的模板

无需修改视图,只需在templates目录下创建对应模板文件(如404.html),Django 会自动使用自定义模板:

<!-- templates/404.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>404 - 页面未找到</title>
</head>
<body><h1>抱歉,你访问的页面不存在!</h1><a href="{% url 'home' %}">返回首页</a>
</body>
</html>

四、请求与响应对象:处理复杂数据交互

Django 封装了HttpRequest(请求)和HttpResponse(响应)对象,用于处理 HTTP 请求的所有信息(如参数、头信息、文件)和返回多样化的响应(如 HTML、JSON、文件)

4.1 HttpRequest对象:获取请求的所有信息

HttpRequest对象由 Django 自动创建,作为视图函数的第一个参数(通常命名为request),包含请求的所有信息

核心属性与方法
属性 / 方法描述示例
request.methodHTTP 请求方法(大写字符串,如'GET''POST'if request.method == 'POST':
request.GETGET 请求参数(QueryDict对象,类似字典)page = request.GET.get('page', 1)
request.POSTPOST 请求参数(表单数据,QueryDict对象)title = request.POST.get('title')
request.META请求头信息(字典,键为大写,前缀HTTP_user_agent = request.META.get('HTTP_USER_AGENT')
request.COOKIES请求中的 Cookie(字典)session_id = request.COOKIES.get('sessionid')
request.FILES上传的文件(MultiValueDict对象)avatar = request.FILES.get('avatar')
request.user当前登录用户(User对象,未登录为AnonymousUserif request.user.is_authenticated:
request.path请求的路径(不含域名和查询参数)/article/1/

实战示例:获取请求数据

def handle_request(request):# 1. 获取请求方法method = request.method  # 'GET' 或 'POST'# 2. 获取GET参数(如 /search/?q=django)search_query = request.GET.get('q', '')  # 默认值为空字符串# 3. 获取POST参数(表单提交)if request.method == 'POST':username = request.POST.get('username')password = request.POST.get('password')# 4. 获取请求头(如用户代理)user_agent = request.META.get('HTTP_USER_AGENT')  # 浏览器信息# 5. 获取上传文件(如头像)avatar = request.FILES.get('avatar')  # 需表单设置 enctype="multipart/form-data"# 6. 获取当前用户if request.user.is_authenticated:user_info = f"当前用户:{request.user.username}"else:user_info = "未登录"return HttpResponse(f"方法:{method}<br>查询:{search_query}<br>{user_info}")

4.2 HttpResponse及其子类:返回多样化响应

HttpResponse是所有响应对象的基类,Django 还提供了多个子类,用于返回特定类型的响应(如 JSON、文件)

(1)基础HttpResponse:返回文本响应

用于返回简单文本、HTML 等响应,可设置响应头和 Cookie

from django.http import HttpResponsedef simple_response(request):# 1. 基础文本响应response = HttpResponse('Hello, Django!', status=200)# 2. 设置响应头response['Content-Type'] = 'text/plain'  # 响应类型response['X-Custom-Header'] = 'MyValue'  # 自定义头# 3. 设置Cookie(max_age单位:秒)response.set_cookie('name', 'Django', max_age=3600)  # 1小时有效期# 4. 删除Cookieresponse.delete_cookie('old_name')return response

(2)JsonResponse:返回 JSON 响应

专门用于返回 JSON 格式的响应(如 API 接口),自动设置Content-Type: application/json,无需手动序列化字典

from django.http import JsonResponsedef api_data(request):# 字典数据(自动序列化为JSON)data = {'status': 'success','data': {'articles': [{'id': 1, 'title': 'Django路由'},{'id': 2, 'title': 'Django视图'}]}}# 返回JSON响应(safe=True表示data必须是字典,否则需设为False)return JsonResponse(data)

返回列表数据(需设safe=False):

def api_list(request):articles = [{'id': 1, 'title': 'Django'}, {'id': 2, 'title': 'Python'}]return JsonResponse(articles, safe=False)  # 列表需设safe=False

(3)StreamingHttpResponse:流式传输大文件

用于返回大型文件(如视频、压缩包),避免一次性加载整个文件到内存,而是分块传输

from django.http import StreamingHttpResponse
import osdef stream_large_file(request):# 大文件路径file_path = os.path.join(settings.MEDIA_ROOT, 'large_file.mp4')file_size = os.path.getsize(file_path)# 定义文件迭代器:分块读取文件def file_iterator(file_path, chunk_size=8192):with open(file_path, 'rb') as f:while True:chunk = f.read(chunk_size)  # 每次读取8KBif not chunk:breakyield chunk# 流式响应response = StreamingHttpResponse(file_iterator(file_path),content_type='video/mp4'  # 视频文件类型)# 设置文件大小(可选,用于进度条)response['Content-Length'] = str(file_size)return response

(4)FileResponse:返回文件下载

StreamingHttpResponse的子类,专门用于返回文件下载,自动处理文件读取和响应头设置

from django.http import FileResponse
import osdef download_file(request):# 文件路径file_path = os.path.join(settings.MEDIA_ROOT, 'document.pdf')# 打开文件(rb:二进制只读)file = open(file_path, 'rb')# 文件响应:自动设置Content-Type和下载头response = FileResponse(file,content_type='application/pdf'  # PDF文件类型)# 设置Content-Disposition:触发浏览器下载(而非预览)response['Content-Disposition'] = 'attachment; filename="document.pdf"'return response

五、模板响应对象:延迟渲染模板

普通render()会立即渲染模板并返回响应,而 “模板响应对象”(SimpleTemplateResponseTemplateResponse)允许在返回响应前延迟渲染模板,并对模板进行后期处理(如修改上下文、添加响应头)

5.1 SimpleTemplateResponse:基础延迟渲染

from django.template.response import SimpleTemplateResponsedef delayed_render(request):# 1. 创建模板响应对象(未渲染)context = {'name': 'Django'}response = SimpleTemplateResponse('index.html', context)# 2. 延迟处理:返回前修改上下文response.context_data['version'] = '5.0'  # 模板中可访问{{ version }}# 3. 返回响应(此时才渲染模板)return response

5.2 TemplateResponse:支持请求上下文

SimpleTemplateResponse的子类,自动包含请求上下文(如request对象、user对象),无需手动传递

from django.template.response import TemplateResponsedef template_response(request):# 创建TemplateResponse,自动包含请求上下文response = TemplateResponse(request, 'index.html', {'name': 'Django'})# 添加“渲染后回调”:模板渲染完成后执行def post_render_callback(response):# 在响应内容末尾添加注释response.content += b' <!-- 渲染完成 -->'return response# 注册回调函数response.add_post_render_callback(post_render_callback)return response

六、文件上传:实现用户上传功能

Django 支持用户上传文件(如头像、附件),需通过 “表单 + 视图” 配合实现,核心是处理request.FILES中的上传文件

6.1 步骤 1:定义文件上传表单

需在表单中设置enctype="multipart/form-data"(否则无法传递文件数据),可使用 Django 的Form类简化表单验证

# myapp/forms.py
from django import formsclass UploadAvatarForm(forms.Form):"""用户头像上传表单"""# FileField:文件上传字段,自动验证文件类型avatar = forms.FileField(label="选择头像",help_text="支持JPG、PNG格式,不超过5MB")# 可选:添加其他字段(如用户名)username = forms.CharField(max_length=100, label="用户名")

6.2 步骤 2:编写上传视图

处理 GET 请求(显示表单)和 POST 请求(处理文件上传),将上传的文件保存到指定目录(如media/avatars/

# myapp/views.py
from django.shortcuts import render, redirect
from .forms import UploadAvatarForm
import os
from django.conf import settingsdef upload_avatar(request):if request.method == 'POST':# 1. 绑定表单数据(request.POST 为普通字段,request.FILES 为文件字段)form = UploadAvatarForm(request.POST, request.FILES)if form.is_valid():# 2. 获取表单数据username = form.cleaned_data['username']avatar_file = request.FILES['avatar']  # 或 form.cleaned_data['avatar']# 3. 保存文件到 media/avatars/ 目录# 构造保存路径(避免文件名重复,可加用户名前缀)save_dir = os.path.join(settings.MEDIA_ROOT, 'avatars')# 确保目录存在(不存在则创建)os.makedirs(save_dir, exist_ok=True)# 保存文件(分块写入,避免内存溢出)with open(os.path.join(save_dir, f"{username}_avatar.jpg"), 'wb+') as destination:for chunk in avatar_file.chunks():  # 分块读取上传文件destination.write(chunk)# 4. 上传成功,重定向到结果页return redirect('upload_success')else:# GET请求:显示空表单form = UploadAvatarForm()# 渲染表单页面return render(request, 'upload_avatar.html', {'form': form})def upload_success(request):"""上传成功页面"""return render(request, 'upload_success.html')

6.3 步骤 3:编写上传模板

<!-- templates/upload_avatar.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>上传头像</title>
</head>
<body><h1>上传用户头像</h1><!-- 必须设置 enctype="multipart/form-data" 才能传递文件 --><form method="post" enctype="multipart/form-data">{% csrf_token %}  <!-- CSRF保护 -->{{ form.as_p }}  <!-- 渲染表单字段(含标签和错误提示) --><button type="submit">上传</button></form>
</body>
</html><!-- templates/upload_success.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><title>上传成功</title>
</head>
<body><h1>头像上传成功!</h1><a href="{% url 'upload_avatar' %}">继续上传</a>
</body>
</html>

6.4 步骤 4:配置媒体文件

确保settings.py中配置了媒体文件路径(参考 3.1 节),并在urls.py中配置媒体文件访问路由

七、总结

本篇覆盖了 Django 视图开发的核心进阶能力,总结如下:

1、快捷函数render()redirect()get_object_or_404()等简化重复逻辑,提升开发效率

2、视图装饰器:控制 HTTP 方法、要求登录 / 权限、缓存页面,增强视图功能

3、请求与响应对象:处理复杂请求数据(如 GET/POST 参数、文件),返回多样化响应(JSON、文件)

4、文件上传:通过表单 + 视图 + 媒体文件配置,实现用户文件上传功能

        掌握这些内容后,你已经能应对大多数 Django 视图开发场景 —— 从简单的页面渲染到复杂的 API 接口、文件处理。结合之前学习的模型与路由知识,你可以搭建起完整的 Django Web 应用骨架,为后续学习模板美化、用户认证等内容打下坚实基础

http://www.dtcms.com/a/464808.html

相关文章:

  • 企业营销网站的建设网站开发响应式
  • 掌握DMA基于GD32F407VE的天空星的配置
  • 基于腾讯云的物联网导盲助手设计与实现(论文+源码)
  • Vue3打造高效前端埋点系统
  • 框架--Maven
  • 【Java集合】
  • 停止Conda开机自动运行方法
  • 湘潭市高新建设局施工报建网站wordpress 宕机
  • 复杂结构数据挖掘(二)关联规则挖掘 Association rule mining
  • Windows 上安装 PostgreSQL
  • 基于JETSON/x86+FPGA+AI的5G远程驾驶座舱时延验证方案
  • 支持向量机(SVM)完全解读
  • 单片机学习日记
  • 重庆网站制作多少钱app设计开发哪家好
  • AI大模型学习(17)python-flask AI大模型和图片处理工具的从一张图到多平台适配的简单方法
  • 如何通过 7 种解决方案将文件从PC无线传输到Android
  • Word 为每一页设置不同页边距(VBA 宏)
  • wordpiece、unigram、sentencepiece基本原理
  • css word-spacing属性
  • 使用 python-docx 库操作 word 文档(2):在word文档中插入各种内容
  • 中企动力销售工作内容白城网站seo
  • 从0死磕全栈之Next.js 企业级 `next.config.js` 配置详解:打造高性能、安全、可维护的中大型项目
  • 在JavaScript中,const和var的区别
  • 【SDR课堂第36讲】RFSOC PS软件开发入门指南(一)
  • 学做网站中国设计网站导航
  • [嵌入式系统-84]:NPU/TPU/LPU有指令集吗?
  • 光伏安全协议-安全责任协议书8篇
  • Java 单元测试全攻略:JUnit 生命周期、覆盖率提升、自动化框架与 Mock 技术
  • SaaS多租户数据隔离实战:MyBatis拦截器实现行级安全方案
  • 【深入理解计算机网络08】网络层之IPv4