django作为python生态中最流行的web框架之一,其视图(view) 与url路由(urlconf) 是连接用户请求与业务逻辑的核心环节。无论是搭建简单的个人博客,还是开发复杂的企业级应用,理解这两大模块的工作原理,都能让我们更高效地构建稳定、易维护的web项目。接下来,我们就从基础概念到实战代码,一步步拆解django视图与路由的核心知识点。
一、django视图基础:连接请求与数据的桥梁
视图是django中处理http请求并返回响应的核心载体,它扮演着“中间件”的角色——一边对接客户端的请求,一边与模型(model)、模板(template)协同工作,最终完成业务逻辑的处理。
1.1 视图的核心职责
- 接收http请求:获取客户端发送的请求信息(如请求方法、参数、头信息等)。
- 与模型交互:从数据库(通过模型)查询或修改数据,比如获取一篇文章、筛选分类列表。
- 传递数据给模板:将模型获取到的数据传递给模板,由模板完成html渲染。
- 返回http响应:将渲染后的页面或json数据等响应结果返回给客户端。
1.2 视图与模型、模板的关系
在django的mvt(model-view-template)架构中,视图是“纽带”:
- 模型(model)提供数据来源,视图通过模型获取数据;
- 模板(template)负责页面展示,视图将数据注入模板并渲染;
- 客户端的请求通过url路由映射到视图,视图处理后返回响应。
二、url路由配置:给请求“指路”的规则
url路由的本质是“url地址”与“视图”的映射关系——当客户端发送一个http请求时,django通过路由规则找到对应的视图,再由视图处理请求。
2.1 路由基础:urlconf的配置方式
django的路由规则定义在项目或应用的urls.py文件中,核心是urlpatterns列表,每个元素通过path()函数映射一个url到对应的视图。
示例(myapp/urls.py):
from django.urls import path
from . import views
# url与视图的映射列表
urlpatterns = [
# 首页:访问http://127.0.0.1:8000/myapp/ 触发views.home视图
path('', views.home, name='home'),
# 文章详情:访问http://127.0.0.1:8000/myapp/article/1/ 触发views.article_detail
path('article/<int:pk>/', views.article_detail, name='article_detail'),
# 分类列表:访问http://127.0.0.1:8000/myapp/category/tech/ 触发views.category_articles
path('category/<slug:slug>/', views.category_articles, name='category_articles'),
]其中name参数是url的“别名”,用于后续的反向解析(避免硬编码url)。
2.2 django处理请求的完整流程
- 客户端发送http请求(如访问
http://127.0.0.1:8000/myapp/article/1/); - django解析url,提取路径部分(即
/myapp/article/1/,忽略域名、查询参数和锚点); - 在
urlpatterns中匹配对应的url模式(如article/<int:pk>/); - 调用匹配到的视图函数(如
views.article_detail),并传递请求对象和url参数(如pk=1); - 视图处理请求后返回响应(如渲染后的文章详情页),django将响应返回给客户端。
2.3 路径转换器:灵活捕获url参数
当需要从url中提取参数(如文章id、分类别名)时,django提供了路径转换器,无需手动解析字符串。常用转换器如下:
| 转换器 | 描述 | 示例 |
|---|---|---|
str | 匹配除斜杠(/)外的任意字符 | path('user/<str:username>/', views.user_profile) |
int | 匹配非负整数(用于id等场景) | path('article/<int:pk>/', views.article_detail) |
slug | 匹配字母、数字、下划线、连字符(url友好的字符串) | path('category/<slug:slug>/', views.category_articles) |
uuid | 匹配uuid格式字符串(用于唯一标识) | path('order/<uuid:order_id>/', views.order_detail) |
path | 匹配包含斜杠的完整路径(用于文件路径等) | path('file/<path:file_path>/', views.file_view) |
示例:通过int:pk获取文章id,视图中接收参数并查询文章:
# views.py
from django.shortcuts import render, get_object_or_404
from .models import article
def article_detail(request, pk):
# 根据pk(文章id)查询文章,不存在则返回404
article = get_object_or_404(article, pk=pk)
# 渲染模板并传递文章数据
return render(request, 'article_detail.html', {'article': article})2.4 正则表达式:处理复杂url模式
对于更灵活的url匹配(如按年月筛选文章归档),可以使用re_path()函数结合正则表达式定义规则。
示例:匹配/article/2025/08/格式的url,提取年份和月份:
# urls.py
from django.urls import re_path
from . import views
urlpatterns = [
# 正则表达式:(?p<year>[0-9]{4}) 表示提取4位数字作为year参数
re_path(r'^article/(?p<year>[0-9]{4})/(?p<month>[0-9]{2})/$', views.article_archive, name='article_archive'),
]
# views.py
def article_archive(request, year, month):
# 筛选指定年月的文章
articles = article.objects.filter(created_at__year=year, created_at__month=month)
return render(request, 'article_archive.html', {'articles': articles, 'year': year, 'month': month})2.5 反向解析:避免硬编码url
在开发中,直接写死url(如/myapp/article/1/)会导致后期修改url时需要全局替换,而反向解析通过url的“别名”(name参数)动态生成url,解决了硬编码问题。
反向解析的两种场景:
在视图中使用:通过reverse()函数生成url。
from django.urls import reverse
def some_view(request):
# 根据别名'article_detail'和参数pk=1生成url:/myapp/article/1/
article_url = reverse('article_detail', args=[1])
# 重定向到该url
return redirect(article_url)在模板中使用:通过{% url %}模板标签生成url。
<!-- 模板中生成文章详情页链接 -->
<a href="{% url 'article_detail' article.pk %}" rel="external nofollow" >{{ article.title }}</a>2.6 命名空间:解决同名url冲突
当多个应用(如blog和shop)都定义了同名的url别名(如index)时,反向解析会无法区分。此时需要通过命名空间隔离不同应用的url。
配置步骤:
应用内定义命名空间:在应用的urls.py中添加app_name。
# blog/urls.py
app_name = 'blog' # 定义应用级命名空间
urlpatterns = [
path('', views.index, name='index'), # 别名index
]项目中关联命名空间:在项目的urls.py中使用namespace参数。
# project/urls.py
from django.urls import path, include
urlpatterns = [
path('blog/', include('blog.urls', namespace='blog')), # 关联命名空间
path('shop/', include('shop.urls', namespace='shop')),
]- 反向解析时指定命名空间:
- 视图中:
reverse('blog:index')(生成/blog/); - 模板中:
{% url 'blog:index' %}。
三、视图函数:业务逻辑的实现载体
视图函数是处理请求的核心代码块,它必须接收request(http请求对象)作为第一个参数,并返回httpresponse(或其子类)对象。
3.1 简单视图函数
最基础的视图函数仅返回一段文本响应:
# views.py
from django.http import httpresponse
def hello(request):
# 返回文本响应
return httpresponse('hello, django!')3.2 错误视图处理
在实际开发中,经常需要返回错误状态码(如404、500)或自定义错误页面。
3.2.1 直接返回错误状态码
from django.http import httpresponse, httpresponsenotfound
# 返回404 not found
def page_not_found(request):
return httpresponsenotfound('页面不存在!')
# 返回204 no content(成功但无内容)
def success_no_content(request):
return httpresponse(status=204)3.2.2 捕获404异常(推荐)
使用get_object_or_404()快捷函数,当查询对象不存在时自动返回404:
from django.shortcuts import get_object_or_404
from .models import article
def article_detail(request, pk):
# 若article不存在(pk不存在),自动抛出404
article = get_object_or_404(article, pk=pk)
return render(request, 'article_detail.html', {'article': article})3.2.3 自定义错误页面
在项目的urls.py中配置全局错误处理器,指定自定义模板:
# project/urls.py
from django.shortcuts import render
# 404页面处理器
def handler404(request, exception):
return render(request, '404.html', status=404)
# 500页面处理器
def handler500(request):
return render(request, '500.html', status=500)3.3 异步视图
django支持异步视图函数(需python 3.7+),适用于io密集型场景(如调用外部api、处理大文件):
import asyncio
from django.http import httpresponse
# 异步视图:使用async def定义
async def async_view(request):
# 模拟io等待(如调用外部api)
await asyncio.sleep(1)
return httpresponse('这是异步视图返回的内容!')四、快捷函数:简化视图开发的“利器”
django提供了多个快捷函数,帮我们减少重复代码,提升开发效率。常用的有4个:
4.1render():渲染模板并返回响应
无需手动创建httpresponse,直接将模板与上下文数据结合并返回响应。
from django.shortcuts import render
def index(request):
# 上下文数据:传递给模板的变量
context = {'name': 'django', 'version': '5.0'}
# 渲染index.html模板,传递context
return render(request, 'index.html', context)4.2redirect():重定向到其他url
支持重定向到命名url、外部链接或视图函数。
from django.shortcuts import redirect
from django.urls import reverse
def redirect_to_home(request):
# 重定向到别名'home'的url
return redirect('home')
def redirect_to_article(request, pk):
# 重定向到带参数的url
return redirect('article_detail', pk=pk)
def redirect_to_external(request):
# 重定向到外部链接
return redirect('https://example.com')4.3get_object_or_404():查询对象或返回404
替代try-except捕获doesnotexist异常,简化查询逻辑(前文已示例)。
4.4get_list_or_404():查询列表或返回404
当查询结果为空时返回404,适用于列表页(如筛选无结果的场景):
from django.shortcuts import get_list_or_404
from .models import article
def published_articles(request):
# 筛选已发布的文章,无结果则返回404
articles = get_list_or_404(article, is_published=true)
return render(request, 'article_list.html', {'articles': articles})五、视图装饰器:增强视图功能的“插件”
视图装饰器用于给视图添加额外功能(如限制请求方法、要求登录、压缩响应),只需在视图函数上方添加@装饰器名即可。
5.1 限制http请求方法
使用require_http_methods、require_get、require_post限制视图接收的请求方法。
from django.views.decorators.http import require_http_methods, require_get, require_post
# 仅允许get和post请求
@require_http_methods(['get', 'post'])
def create_article(request):
if request.method == 'get':
# 显示创建表单
return render(request, 'article_form.html')
elif request.method == 'post':
# 处理表单提交
pass
# 仅允许get请求
@require_get
def article_list(request):
pass
# 仅允许post请求
@require_post
def delete_article(request):
pass5.2 其他常用装饰器
@login_required:要求用户登录后才能访问视图(未登录则跳转登录页)。
from django.contrib.auth.decorators import login_required
@login_required
def user_profile(request):
# 仅登录用户可访问个人中心
pass@permission_required:要求用户拥有指定权限才能访问。
from django.contrib.auth.decorators import permission_required
# 要求用户有"修改文章"的权限
@permission_required('myapp.change_article')
def edit_article(request, pk):
pass@gzip_page:压缩视图返回的响应内容,节省带宽。
from django.views.decorators.gzip import gzip_page
@gzip_page
def large_page(request):
# 压缩大页面的响应
pass六、请求与响应对象:与客户端的“对话”
django通过httprequest和httpresponse对象封装请求与响应的所有信息,是视图与客户端交互的核心载体。
6.1 httprequest对象:获取请求信息
request参数是httprequest的实例,包含请求的所有信息,常用属性如下:
request.method:请求方法(如'get'、'post')。request.get:get请求参数(类似字典,用get()获取值)。
# 获取url中的查询参数:?name=django
name = request.get.get('name')request.post:post请求参数(表单提交的数据)。
# 获取表单中的email字段
email = request.post.get('email')request.meta:请求头信息(如user-agent、ip地址)。
# 获取用户浏览器信息
user_agent = request.meta.get('http_user_agent')
# 获取客户端ip
ip = request.meta.get('remote_addr')request.cookies:客户端的cookie信息。request.files:客户端上传的文件(需表单enctype="multipart/form-data")。request.user:当前登录的用户对象(未登录则为匿名用户)。
6.2 httpresponse对象:构造响应内容
httpresponse是所有响应的基类,常用子类如下:
httpresponse:基础文本响应(前文已示例)。jsonresponse:返回json数据(适用于api接口)。
from django.http import jsonresponse
def api_data(request):
data = {
'name': 'django',
'features': ['orm', 'admin', 'templates']
}
return jsonresponse(data) # 自动设置content-type: application/jsonfileresponse:返回文件下载(streaminghttpresponse的子类,优化大文件传输)。
from django.http import fileresponse
import os
def download_pdf(request):
file_path = '/path/to/document.pdf'
# 打开文件并返回下载响应
response = fileresponse(open(file_path, 'rb'))
# 设置下载文件名
response['content-disposition'] = 'attachment; filename="document.pdf"'
return response七、文件上传:实现用户文件提交
django处理文件上传需三步:配置表单、编写视图、保存文件。
7.1 定义文件上传表单
需设置表单的enctype="multipart/form-data"(否则无法接收文件):
# forms.py
from django import forms
class uploadfileform(forms.form):
title = forms.charfield(max_length=50) # 文件标题
file = forms.filefield() # 文件上传字段7.2 编写视图处理上传
在视图中通过request.files获取上传的文件,并分块保存(避免内存溢出):
# views.py
from django.shortcuts import render
from .forms import uploadfileform
import os
def upload_file(request):
if request.method == 'post':
# 初始化表单并传递post数据和文件
form = uploadfileform(request.post, request.files)
if form.is_valid():
title = form.cleaned_data['title']
uploaded_file = request.files['file'] # 获取上传的文件
# 分块保存文件(适合大文件)
upload_dir = 'uploads/'
os.makedirs(upload_dir, exist_ok=true) # 确保目录存在
with open(os.path.join(upload_dir, uploaded_file.name), 'wb+') as f:
for chunk in uploaded_file.chunks():
f.write(chunk)
# 上传成功,跳转成功页
return render(request, 'upload_success.html')
else:
# get请求:显示空表单
form = uploadfileform()
return render(request, 'upload.html', {'form': form})7.3 模板渲染表单
<!-- upload.html -->
<form method="post" enctype="multipart/form-data">
{% csrf_token %} <!-- 必须添加,防止csrf攻击 -->
{{ form.as_p }} <!-- 渲染表单字段 -->
<button type="submit">上传</button>
</form>到此这篇关于python中的django视图与路由的文章就介绍到这了,更多相关django视图与路由内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论