Skip to content

第13章:完整博客系统

13.2 核心功能实现

文章CRUD

实现文章的创建、读取、更新、删除功能:

python
# views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib import messages
from .models import Article, Category, Tag
from .forms import ArticleForm

class ArticleListView(ListView):
    model = Article
    template_name = 'blog/article_list.html'
    context_object_name = 'articles'
    paginate_by = 10
    
    def get_queryset(self):
        return Article.objects.filter(status='published').select_related('author', 'category')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['categories'] = Category.objects.all()
        context['tags'] = Tag.objects.all()
        return context

class ArticleDetailView(DetailView):
    model = Article
    template_name = 'blog/article_detail.html'
    context_object_name = 'article'
    
    def get_queryset(self):
        return Article.objects.select_related('author', 'category').prefetch_related('tags')
    
    def get_object(self, queryset=None):
        article = super().get_object(queryset)
        # 增加浏览量
        article.view_count += 1
        article.save(update_fields=['view_count'])
        return article
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 获取相关文章
        context['related_articles'] = Article.objects.filter(
            category=self.object.category,
            status='published'
        ).exclude(pk=self.object.pk)[:5]
        return context

class ArticleCreateView(LoginRequiredMixin, CreateView):
    model = Article
    form_class = ArticleForm
    template_name = 'blog/article_form.html'
    
    def form_valid(self, form):
        form.instance.author = self.request.user
        response = super().form_valid(form)
        messages.success(self.request, '文章创建成功!')
        return response

class ArticleUpdateView(LoginRequiredMixin, UpdateView):
    model = Article
    form_class = ArticleForm
    template_name = 'blog/article_form.html'
    
    def get_queryset(self):
        # 用户只能编辑自己的文章
        return Article.objects.filter(author=self.request.user)
    
    def form_valid(self, form):
        response = super().form_valid(form)
        messages.success(self.request, '文章更新成功!')
        return response

class ArticleDeleteView(LoginRequiredMixin, DeleteView):
    model = Article
    template_name = 'blog/article_confirm_delete.html'
    success_url = reverse_lazy('blog:article_list')
    
    def get_queryset(self):
        # 用户只能删除自己的文章
        return Article.objects.filter(author=self.request.user)
    
    def delete(self, request, *args, **kwargs):
        messages.success(self.request, '文章删除成功!')
        return super().delete(request, *args, **kwargs)

# forms.py
from django import forms
from .models import Article, Category, Tag

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = ['title', 'category', 'tags', 'content', 'excerpt', 'featured_image', 'status']
        widgets = {
            'title': forms.TextInput(attrs={'class': 'form-control'}),
            'category': forms.Select(attrs={'class': 'form-control'}),
            'tags': forms.SelectMultiple(attrs={'class': 'form-control'}),
            'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 15}),
            'excerpt': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
            'featured_image': forms.FileInput(attrs={'class': 'form-control'}),
            'status': forms.Select(attrs={'class': 'form-control'}),
        }
    
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['tags'].widget.attrs.update({'size': '10'})

分类和标签

实现分类和标签功能:

python
# views.py
class CategoryDetailView(ListView):
    model = Article
    template_name = 'blog/category_detail.html'
    context_object_name = 'articles'
    paginate_by = 10
    
    def get_queryset(self):
        self.category = get_object_or_404(Category, slug=self.kwargs['slug'])
        return Article.objects.filter(
            category=self.category,
            status='published'
        ).select_related('author', 'category')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['category'] = self.category
        return context

class TagDetailView(ListView):
    model = Article
    template_name = 'blog/tag_detail.html'
    context_object_name = 'articles'
    paginate_by = 10
    
    def get_queryset(self):
        self.tag = get_object_or_404(Tag, slug=self.kwargs['slug'])
        return Article.objects.filter(
            tags=self.tag,
            status='published'
        ).select_related('author', 'category')
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['tag'] = self.tag
        return context

评论系统

实现评论功能:

python
# models.py
class Comment(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='comments')
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='comments')
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='replies')
    content = models.TextField()
    is_approved = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        ordering = ['created_at']
    
    def __str__(self):
        return f'{self.author.username}{self.article.title} 的评论'

# forms.py
class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = ['content']
        widgets = {
            'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 4, 'placeholder': '请输入您的评论...'}),
        }

# views.py
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse

@login_required
def add_comment(request, article_id):
    article = get_object_or_404(Article, id=article_id)
    
    if request.method == 'POST':
        form = CommentForm(request.POST)
        if form.is_valid():
            comment = form.save(commit=False)
            comment.article = article
            comment.author = request.user
            comment.save()
            messages.success(request, '评论发表成功!')
            return redirect('blog:article_detail', slug=article.slug)
    
    return redirect('blog:article_detail', slug=article.slug)

class ArticleDetailView(DetailView):
    # ... 其他代码 ...
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        # 获取评论
        context['comments'] = self.object.comments.filter(
            is_approved=True,
            parent=None
        ).select_related('author').prefetch_related('replies__author')
        context['comment_form'] = CommentForm()
        return context

搜索功能

实现文章搜索功能:

python
# views.py
from django.db.models import Q

class SearchView(ListView):
    model = Article
    template_name = 'blog/search_results.html'
    context_object_name = 'articles'
    paginate_by = 10
    
    def get_queryset(self):
        query = self.request.GET.get('q')
        if query:
            return Article.objects.filter(
                Q(title__icontains=query) |
                Q(content__icontains=query) |
                Q(excerpt__icontains=query)
            ).filter(status='published').select_related('author', 'category').distinct()
        return Article.objects.none()
    
    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['query'] = self.request.GET.get('q', '')
        return context

小结

博客系统核心功能实现的关键点:

  1. ✅ 使用Django的通用视图简化CRUD操作
  2. ✅ 实现文章分类和标签的展示功能
  3. ✅ 构建完整的评论系统支持回复功能
  4. ✅ 开发高效的搜索功能
  5. ✅ 注重用户体验和数据安全性

通过这些核心功能的实现,博客系统已具备基本的使用价值。

下一篇

我们将实现博客系统的高级功能。

13.3 高级功能 →

目录

返回课程目录

Released under the Apache 2.0 License.