Python中的Django视图与路由

Written by

in

文章目录
  • 视图是Django中处理HTTP请求并返回响应的核心载体,它扮演着“中间件”的角色——一边对接客户端的请求,一边与模型(Model)、模板(Template)协同工作,最终完成业务逻辑的处理。
  • URL路由的本质是“URL地址”与“视图”的映射关系——当客户端发送一个HTTP请求时,Django通过路由规则找到对应的视图,再由视图处理请求。
  • 视图函数是处理请求的核心代码块,它必须接收request(HTTP请求对象)作为第一个参数,并返回HttpResponse(或其子类)对象。
  • Django提供了多个快捷函数,帮我们减少重复代码,提升开发效率。常用的有4个:
  • 视图装饰器用于给视图添加额外功能(如限制请求方法、要求登录、压缩响应),只需在视图函数上方添加@装饰器名即可。
  • Django通过HttpRequest和HttpResponse对象封装请求与响应的所有信息,是视图与客户端交互的核心载体。
  • Django处理文件上传需三步:配置表单、编写视图、保存文件。
  • 目录
    • 一、Django视图基础:连接请求与数据的桥梁
      • 1.1 视图的核心职责
      • 1.2 视图与模型、模板的关系
    • 二、URL路由配置:给请求“指路”的规则
      • 2.1 路由基础:URLconf的配置方式
      • 2.2 Django处理请求的完整流程
      • 2.3 路径转换器:灵活捕获URL参数
      • 2.4 正则表达式:处理复杂URL模式
      • 2.5 反向解析:避免硬编码URL
        • 反向解析的两种场景:
      • 2.6 命名空间:解决同名URL冲突
        • 配置步骤:
    • 三、视图函数:业务逻辑的实现载体
      • 3.1 简单视图函数
        • 3.2 错误视图处理
          • 3.2.1 直接返回错误状态码
          • 3.2.2 捕获404异常(推荐)
          • 3.2.3 自定义错误页面
        • 3.3 异步视图
        • 四、快捷函数:简化视图开发的“利器”
          • 4.1render():渲染模板并返回响应
            • 4.2redirect():重定向到其他URL
              • 4.3get_object_or_404():查询对象或返回404
                • 4.4get_list_or_404():查询列表或返回404
                • 五、视图装饰器:增强视图功能的“插件”
                  • 5.1 限制HTTP请求方法
                    • 5.2 其他常用装饰器
                    • 六、请求与响应对象:与客户端的“对话”
                      • 6.1 HttpRequest对象:获取请求信息
                        • 6.2 HttpResponse对象:构造响应内容
                        • 七、文件上传:实现用户文件提交
                          • 7.1 定义文件上传表单
                            • 7.2 编写视图处理上传
                              • 7.3 模板渲染表单

                              Django作为Python生态中最流行的Web框架之一,其视图(View)URL路由(URLconf) 是连接用户请求与业务逻辑的核心环节。无论是搭建简单的个人博客,还是开发复杂的企业级应用,理解这两大模块的工作原理,都能让我们更高效地构建稳定、易维护的Web项目。接下来,我们就从基础概念到实战代码,一步步拆解Django视图与路由的核心知识点。

                              视图是Django中处理HTTP请求并返回响应的核心载体,它扮演着“中间件”的角色——一边对接客户端的请求,一边与模型(Model)、模板(Template)协同工作,最终完成业务逻辑的处理。

                              • 接收HTTP请求:获取客户端发送的请求信息(如请求方法、参数、头信息等)。
                              • 与模型交互:从数据库(通过模型)查询或修改数据,比如获取一篇文章、筛选分类列表。
                              • 传递数据给模板:将模型获取到的数据传递给模板,由模板完成HTML渲染。
                              • 返回HTTP响应:将渲染后的页面或JSON数据等响应结果返回给客户端。

                              在Django的MVT(Model-View-Template)架构中,视图是“纽带”:

                              • 模型(Model)提供数据来源,视图通过模型获取数据;
                              • 模板(Template)负责页面展示,视图将数据注入模板并渲染;
                              • 客户端的请求通过URL路由映射到视图,视图处理后返回响应。

                              URL路由的本质是“URL地址”与“视图”的映射关系——当客户端发送一个HTTP请求时,Django通过路由规则找到对应的视图,再由视图处理请求。

                              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)。

                              1. 客户端发送HTTP请求(如访问http://127.0.0.1:8000/myapp/article/1/);
                              2. Django解析URL,提取路径部分(即/myapp/article/1/,忽略域名、查询参数和锚点);
                              3. urlpatterns中匹配对应的URL模式(如article/<int:pk>/);
                              4. 调用匹配到的视图函数(如views.article_detail),并传递请求对象和URL参数(如pk=1);
                              5. 视图处理请求后返回响应(如渲染后的文章详情页),Django将响应返回给客户端。

                              当需要从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})

                              对于更灵活的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})

                              在开发中,直接写死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>

                              当多个应用(如blogshop)都定义了同名的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(或其子类)对象。

                              最基础的视图函数仅返回一段文本响应:

                              # views.py
                              from django.http import HttpResponse
                              def hello(request):
                                  # 返回文本响应
                                  return HttpResponse('Hello, Django!')

                              在实际开发中,经常需要返回错误状态码(如404、500)或自定义错误页面。

                              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)

                              使用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})

                              在项目的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)

                              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个:

                              无需手动创建HttpResponse,直接将模板与上下文数据结合并返回响应。

                              from django.shortcuts import render
                              def index(request):
                                  # 上下文数据:传递给模板的变量
                                  context = {'name': 'Django', 'version': '5.0'}
                                  # 渲染index.html模板,传递context
                                  return render(request, 'index.html', context)

                              支持重定向到命名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')

                              替代try-except捕获DoesNotExist异常,简化查询逻辑(前文已示例)。

                              当查询结果为空时返回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})

                              视图装饰器用于给视图添加额外功能(如限制请求方法、要求登录、压缩响应),只需在视图函数上方添加@装饰器名即可。

                              使用require_http_methodsrequire_GETrequire_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):
                                  pass

                              @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通过HttpRequestHttpResponse对象封装请求与响应的所有信息,是视图与客户端交互的核心载体。

                              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:当前登录的用户对象(未登录则为匿名用户)。

                              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/json
                              • FileResponse:返回文件下载(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处理文件上传需三步:配置表单、编写视图、保存文件。

                              需设置表单的enctype="multipart/form-data"(否则无法接收文件):

                              # forms.py
                              from django import forms
                              class UploadFileForm(forms.Form):
                                  title = forms.CharField(max_length=50)  # 文件标题
                                  file = forms.FileField()  # 文件上传字段

                              在视图中通过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})

                              <!-- upload.html -->
                              <form method="post" enctype="multipart/form-data">
                                  {% csrf_token %}  <!-- 必须添加,防止CSRF攻击 -->
                                  {{ form.as_p }}   <!-- 渲染表单字段 -->
                                  <button type="submit">上传</button>
                              </form>

                              到此这篇关于Python中的Django视图与路由的文章就介绍到这了,更多相关Django视图与路由内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

                              您可能感兴趣的文章:

                              • Django中的函数视图和类视图以及路由的定义方式
                              • Django视图与URLs路由的使用方式
                              • Django在urls.py利用函数path()配置路由时传递参数给调用的视图函数的方法(推荐)
                              • python之django路由和视图案例教程
                              • django drf框架自带的路由及最简化的视图
                              • Django REST framework 视图和路由详解

                              站内搜索