第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小结
博客系统核心功能实现的关键点:
- ✅ 使用Django的通用视图简化CRUD操作
- ✅ 实现文章分类和标签的展示功能
- ✅ 构建完整的评论系统支持回复功能
- ✅ 开发高效的搜索功能
- ✅ 注重用户体验和数据安全性
通过这些核心功能的实现,博客系统已具备基本的使用价值。
下一篇
我们将实现博客系统的高级功能。