每天40分玩转Django:Django类视图

发布于:2024-12-23 ⋅ 阅读:(18) ⋅ 点赞:(0)

Django类视图

一、今日学习内容概述

学习模块 重要程度 主要内容
类视图基础 ⭐⭐⭐⭐⭐ View类、URLconf配置
通用视图 ⭐⭐⭐⭐⭐ ListView、DetailView等
Mixin机制 ⭐⭐⭐⭐ 多重继承、功能组合
自定义类视图 ⭐⭐⭐⭐ 视图定制、方法重写

二、类视图基础

2.1 基本类视图

# views.py
from django.views import View
from django.http import HttpResponse
from django.shortcuts import render

class HelloView(View):
    def get(self, request, *args, **kwargs):
        return HttpResponse('Hello, World!')
        
class HomeView(View):
    template_name = 'home.html'
    
    def get(self, request):
        context = {
            'title': '首页',
            'message': '欢迎访问'
        }
        return render(request, self.template_name, context)
        
    def post(self, request):
        # 处理POST请求
        data = request.POST.get('data')
        # 处理数据...
        return HttpResponse('数据已处理')

2.2 URL配置

# urls.py
from django.urls import path
from .views import HelloView, HomeView

urlpatterns = [
    path('hello/', HelloView.as_view(), name='hello'),
    path('', HomeView.as_view(), name='home'),
]

三、通用类视图实现

3.1 列表视图和详情视图

# models.py
from django.db import models

class Article(models.Model):
    title = models.CharField('标题', max_length=200)
    content = models.TextField('内容')
    created_at = models.DateTimeField('创建时间', auto_now_add=True)
    updated_at = models.DateTimeField('更新时间', auto_now=True)
    author = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    
    def __str__(self):
        return self.title

# views.py
from django.views.generic import ListView, DetailView
from .models import Article

class ArticleListView(ListView):
    model = Article
    template_name = 'blog/article_list.html'
    context_object_name = 'articles'
    paginate_by = 10
    
    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.select_related('author')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['total_articles'] = self.get_queryset().count()
        return context

class ArticleDetailView(DetailView):
    model = Article
    template_name = 'blog/article_detail.html'
    context_object_name = 'article'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 添加相关文章
        context['related_articles'] = Article.objects.filter(
            author=self.object.author
        ).exclude(id=self.object.id)[:5]
        return context

3.2 创建和编辑视图

from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy

class ArticleCreateView(LoginRequiredMixin, CreateView):
    model = Article
    template_name = 'blog/article_form.html'
    fields = ['title', 'content']
    success_url = reverse_lazy('article_list')
    
    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

class ArticleUpdateView(LoginRequiredMixin, UpdateView):
    model = Article
    template_name = 'blog/article_form.html'
    fields = ['title', 'content']
    
    def get_queryset(self):
        # 只允许作者编辑自己的文章
        return super().get_queryset().filter(author=self.request.user)
    
    def get_success_url(self):
        return reverse_lazy('article_detail', kwargs={'pk': self.object.pk})

class ArticleDeleteView(LoginRequiredMixin, DeleteView):
    model = Article
    template_name = 'blog/article_confirm_delete.html'
    success_url = reverse_lazy('article_list')

四、Mixin机制实现

# mixins.py
from django.contrib import messages
from django.shortcuts import redirect

class AuthorRequiredMixin:
    """确保只有作者可以编辑内容"""
    def dispatch(self, request, *args, **kwargs):
        obj = self.get_object()
        if obj.author != request.user:
            messages.error(request, '您没有权限执行此操作')
            return redirect('article_list')
        return super().dispatch(request, *args, **kwargs)

class TitleSearchMixin:
    """添加标题搜索功能"""
    def get_queryset(self):
        queryset = super().get_queryset()
        search_query = self.request.GET.get('search')
        if search_query:
            queryset = queryset.filter(title__icontains=search_query)
        return queryset
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['search_query'] = self.request.GET.get('search', '')
        return context

# 使用Mixin
class ArticleListView(TitleSearchMixin, ListView):
    model = Article
    template_name = 'blog/article_list.html'
    context_object_name = 'articles'
    paginate_by = 10

class ArticleUpdateView(LoginRequiredMixin, AuthorRequiredMixin, UpdateView):
    model = Article
    template_name = 'blog/article_form.html'
    fields = ['title', 'content']

五、类视图流程图

在这里插入图片描述

六、高级类视图示例

6.1 自定义视图组合

from django.views.generic import TemplateView
from django.views.generic.dates import (
    YearArchiveView,
    MonthArchiveView,
    DayArchiveView
)

class ArticleArchiveView(TemplateView):
    template_name = 'blog/article_archive.html'
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['years'] = Article.objects.dates('created_at', 'year', order='DESC')
        return context

class ArticleYearArchiveView(YearArchiveView):
    model = Article
    date_field = 'created_at'
    make_object_list = True
    template_name = 'blog/article_archive_year.html'

class ArticleMonthArchiveView(MonthArchiveView):
    model = Article
    date_field = 'created_at'
    template_name = 'blog/article_archive_month.html'

6.2 表单处理视图

from django.views.generic.edit import FormView
from django import forms

class ContactForm(forms.Form):
    name = forms.CharField(max_length=100)
    email = forms.EmailField()
    message = forms.CharField(widget=forms.Textarea)

class ContactView(FormView):
    template_name = 'contact.html'
    form_class = ContactForm
    success_url = '/thanks/'
    
    def form_valid(self, form):
        # 发送邮件
        name = form.cleaned_data['name']
        email = form.cleaned_data['email']
        message = form.cleaned_data['message']
        # 处理表单数据...
        messages.success(self.request, '消息已发送')
        return super().form_valid(form)

七、类视图最佳实践

  1. 视图分组和组织
# views/__init__.py
from .article import ArticleListView, ArticleDetailView
from .archive import ArticleArchiveView
from .contact import ContactView

# views/article.py
class ArticleViews:
    """文章相关视图"""
    
# views/archive.py
class ArchiveViews:
    """归档相关视图"""
  1. 通用功能抽象
class BaseView(View):
    """基础视图类,包含通用功能"""
    def dispatch(self, request, *args, **kwargs):
        # 添加通用处理逻辑
        return super().dispatch(request, *args, **kwargs)

class BaseCRUDView(BaseView):
    """CRUD操作基础视图"""
    model = None
    form_class = None
  1. 权限控制
from django.contrib.auth.mixins import (
    LoginRequiredMixin,
    PermissionRequiredMixin
)

class StaffRequiredMixin(LoginRequiredMixin):
    """要求用户是员工"""
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_staff:
            messages.error(request, '需要员工权限')
            return redirect('home')
        return super().dispatch(request, *args, **kwargs)

八、测试类视图

from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth.models import User

class ArticleViewTests(TestCase):
    def setUp(self):
        self.client = Client()
        self.user = User.objects.create_user(
            username='testuser',
            password='testpass123'
        )
        
    def test_article_list_view(self):
        response = self.client.get(reverse('article_list'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'blog/article_list.html')
        
    def test_article_create_view(self):
        # 未登录用户
        response = self.client.get(reverse('article_create'))
        self.assertEqual(response.status_code, 302)  # 重定向到登录页
        
        # 登录用户
        self.client.login(username='testuser', password='testpass123')
        response = self.client.get(reverse('article_create'))
        self.assertEqual(response.status_code, 200)

通过本章学习,你应该能够:

  1. 理解类视图的工作原理
  2. 使用Django的通用视图
  3. 创建自定义类视图
  4. 使用Mixin机制扩展功能

怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!