Django View视图层详解

课程目标

  • 理解Django视图的概念和作用
  • 掌握函数视图和类视图的使用
  • 学会处理HTTP请求和响应
  • 了解Django的URL配置机制

视图简介

Django视图是处理HTTP请求并返回HTTP响应的函数或类。视图位于Django MTV架构的"V"层(View),负责处理业务逻辑并返回响应给用户。

视图的职责:

  • 接收HTTP请求
  • 处理业务逻辑
  • 返回HTTP响应

函数视图(Function-Based Views)

基本函数视图

from django.http import HttpResponse
import datetime

def current_datetime(request):
    now = datetime.datetime.now()
    html = f"<html><body>现在是 {now}</body></html>"
    return HttpResponse(html)

使用模板的函数视图

from django.shortcuts import render
from django.http import HttpResponse

def article_list(request):
    articles = Article.objects.all()
    context = {'articles': articles}
    return render(request, 'articles/list.html', context)

处理POST请求

from django.shortcuts import render, redirect
from django.contrib import messages

def create_article(request):
    if request.method == 'POST':
        title = request.POST.get('title')
        content = request.POST.get('content')
        
        # 保存到数据库
        article = Article.objects.create(
            title=title,
            content=content,
            author=request.user
        )
        
        messages.success(request, '文章创建成功!')
        return redirect('article_detail', id=article.id)
    
    return render(request, 'articles/create.html')

类视图(Class-Based Views)

基本类视图

from django.views import View
from django.http import HttpResponse

class HelloView(View):
    def get(self, request):
        return HttpResponse('Hello, World!')
    
    def post(self, request):
        return HttpResponse('Received POST request')

通用视图

from django.views.generic import ListView, DetailView, CreateView
from django.urls import reverse_lazy

class ArticleListView(ListView):
    model = Article
    template_name = 'articles/list.html'
    context_object_name = 'articles'
    paginate_by = 10
    
    def get_queryset(self):
        return Article.objects.filter(is_published=True)

class ArticleDetailView(DetailView):
    model = Article
    template_name = 'articles/detail.html'
    context_object_name = 'article'

class ArticleCreateView(CreateView):
    model = Article
    fields = ['title', 'content', 'category']
    template_name = 'articles/create.html'
    success_url = reverse_lazy('article_list')

HTTP请求处理

请求对象属性

def handle_request(request):
    # 请求方法
    method = request.method
    
    # GET参数
    search = request.GET.get('search', '')
    
    # POST数据
    username = request.POST.get('username', '')
    
    # 请求头
    user_agent = request.META.get('HTTP_USER_AGENT', '')
    
    # 用户信息
    user = request.user
    
    # 会话信息
    session_data = request.session.get('key', 'default')
    
    # IP地址
    ip_address = request.META.get('REMOTE_ADDR', '')

请求方法处理

def article_manage(request, article_id):
    try:
        article = Article.objects.get(id=article_id)
    except Article.DoesNotExist:
        return HttpResponse('文章不存在', status=404)
    
    if request.method == 'GET':
        # 显示文章详情
        context = {'article': article}
        return render(request, 'articles/detail.html', context)
    
    elif request.method == 'POST':
        # 更新文章
        article.title = request.POST.get('title')
        article.content = request.POST.get('content')
        article.save()
        return redirect('article_detail', id=article.id)
    
    elif request.method == 'DELETE':
        # 删除文章
        article.delete()
        return HttpResponse('删除成功')
    
    else:
        return HttpResponse('不支持的请求方法', status=405)

响应处理

基本响应

from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
from django.shortcuts import redirect

def basic_responses(request):
    # 简单响应
    response = HttpResponse("Hello, World!")
    
    # JSON响应
    data = {'status': 'success', 'message': '操作成功'}
    return JsonResponse(data)
    
    # 重定向
    return redirect('/home/')
    # 或者
    return HttpResponseRedirect('/home/')

模板响应

from django.shortcuts import render, get_object_or_404

def article_detail(request, article_id):
    # 使用get_object_or_404自动处理不存在的情况
    article = get_object_or_404(Article, id=article_id)
    
    context = {
        'article': article,
        'comments': article.comments.all(),
    }
    
    return render(request, 'articles/detail.html', context)

URL配置

URL模式定义

# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('articles/', views.ArticleListView.as_view(), name='article_list'),
    path('articles/<int:article_id>/', views.article_detail, name='article_detail'),
    path('articles/create/', views.ArticleCreateView.as_view(), name='article_create'),
    path('articles/<int:pk>/edit/', views.ArticleUpdateView.as_view(), name='article_update'),
    path('articles/<int:pk>/delete/', views.ArticleDeleteView.as_view(), name='article_delete'),
]

URL参数传递

# 在urls.py中定义带参数的URL
path('articles/<int:article_id>/', views.article_detail, name='article_detail'),
path('articles/<slug:slug>/', views.article_by_slug, name='article_by_slug'),
path('articles/<int:year>/<int:month>/', views.articles_by_date, name='articles_by_date'),

# 在视图中接收参数
def article_detail(request, article_id):
    article = get_object_or_404(Article, id=article_id)
    return render(request, 'articles/detail.html', {'article': article})

def articles_by_date(request, year, month):
    articles = Article.objects.filter(
        pub_date__year=year,
        pub_date__month=month
    )
    return render(request, 'articles/list.html', {'articles': articles})

装饰器使用

常用装饰器

from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_http_methods, require_GET, require_POST
from django.views.decorators.csrf import csrf_exempt

@login_required
def protected_view(request):
    """需要登录才能访问"""
    return render(request, 'protected.html')

@require_POST
def create_article(request):
    """只接受POST请求"""
    # 处理创建逻辑
    pass

@csrf_exempt
def webhook_view(request):
    """免除CSRF检查"""
    # Webhook处理逻辑
    pass

错误处理

自定义错误页面

# views.py
def custom_404(request, exception):
    return render(request, 'errors/404.html', status=404)

def custom_500(request):
    return render(request, 'errors/500.html', status=500)

# 在urls.py中配置
handler404 = 'myapp.views.custom_404'
handler500 = 'myapp.views.custom_500'

视图最佳实践

视图组织原则

  • 保持视图函数简洁,将复杂逻辑移到模型或服务层
  • 合理使用通用视图减少重复代码
  • 正确处理异常和错误情况
  • 使用适当的HTTP状态码

示例:良好实践的视图

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.db import transaction

@login_required
@transaction.atomic
def update_article(request, article_id):
    article = get_object_or_404(Article, id=article_id)
    
    # 检查权限
    if article.author != request.user:
        messages.error(request, '您没有权限编辑这篇文章')
        return redirect('article_detail', id=article.id)
    
    if request.method == 'POST':
        try:
            article.title = request.POST.get('title', '').strip()
            article.content = request.POST.get('content', '')
            
            if not article.title:
                messages.error(request, '标题不能为空')
                return render(request, 'articles/edit.html', {'article': article})
            
            article.save()
            messages.success(request, '文章更新成功')
            return redirect('article_detail', id=article.id)
            
        except Exception as e:
            messages.error(request, f'更新失败:{str(e)}')
    
    return render(request, 'articles/edit.html', {'article': article})

课程总结

本节课我们学习了Django的视图层,包括函数视图和类视图的使用、HTTP请求和响应的处理、URL配置等内容。视图是Django应用的核心组成部分,掌握视图的使用对构建Web应用至关重要。