实操博客应用
一、内容概述
模块 | 重要程度 | 主要内容 |
---|---|---|
项目初始化 | ⭐⭐⭐⭐ | 创建项目和应用 |
模型设计 | ⭐⭐⭐⭐⭐ | 文章、评论、用户模型 |
视图实现 | ⭐⭐⭐⭐⭐ | 增删改查功能 |
模板开发 | ⭐⭐⭐⭐ | 页面布局和样式 |
用户认证 | ⭐⭐⭐⭐⭐ | 用户登录和权限 |
二、项目结构
blog_project/
├── blog/
│ ├── __init__.py
│ ├── models.py
│ ├── views.py
│ ├── urls.py
│ ├── forms.py
│ └── templates/
│ └── blog/
│ ├── base.html
│ ├── post_list.html
│ ├── post_detail.html
│ └── post_form.html
├── static/
│ └── css/
│ └── style.css
└── manage.py
三、模型设计
# blog/models.py
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.utils import timezone
class Category(models.Model):
name = models.CharField('分类名', max_length=100)
created_at = models.DateTimeField('创建时间', auto_now_add=True)
class Meta:
verbose_name = '分类'
verbose_name_plural = verbose_name
def __str__(self):
return self.name
class Post(models.Model):
STATUS_CHOICES = [
('draft', '草稿'),
('published', '发布'),
]
title = models.CharField('标题', max_length=200)
slug = models.SlugField('URL', max_length=200, unique_for_date='publish')
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='blog_posts',
verbose_name='作者'
)
category = models.ForeignKey(
Category,
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='posts',
verbose_name='分类'
)
content = models.TextField('内容')
publish = models.DateTimeField('发布时间', default=timezone.now)
created = models.DateTimeField('创建时间', auto_now_add=True)
updated = models.DateTimeField('更新时间', auto_now=True)
status = models.CharField(
'状态',
max_length=10,
choices=STATUS_CHOICES,
default='draft'
)
views = models.PositiveIntegerField('浏览量', default=0)
class Meta:
ordering = ('-publish',)
verbose_name = '文章'
verbose_name_plural = verbose_name
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail', args=[
self.publish.year,
self.publish.strftime('%m'),
self.publish.strftime('%d'),
self.slug
])
class Comment(models.Model):
post = models.ForeignKey(
Post,
on_delete=models.CASCADE,
related_name='comments',
verbose_name='文章'
)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='comments',
verbose_name='作者'
)
content = models.TextField('评论内容')
created = models.DateTimeField('创建时间', auto_now_add=True)
active = models.BooleanField('是否可见', default=True)
parent = models.ForeignKey(
'self',
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='replies',
verbose_name='父评论'
)
class Meta:
ordering = ('created',)
verbose_name = '评论'
verbose_name_plural = verbose_name
def __str__(self):
return f'Comment by {self.author} on {self.post}'
四、表单设计
# blog/forms.py
from django import forms
from .models import Post, Comment
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'slug', 'content', 'category', 'status']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'slug': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'class': 'form-control'}),
'category': forms.Select(attrs={'class': 'form-control'}),
'status': forms.Select(attrs={'class': 'form-control'}),
}
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['content']
widgets = {
'content': forms.Textarea(attrs={
'class': 'form-control',
'rows': 4,
'placeholder': '请输入评论内容'
}),
}
五、视图实现
# blog/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.core.paginator import Paginator
from django.contrib import messages
from .models import Post, Comment, Category
from .forms import PostForm, CommentForm
def post_list(request):
post_list = Post.objects.filter(status='published')
paginator = Paginator(post_list, 10)
page_number = request.GET.get('page')
posts = paginator.get_page(page_number)
categories = Category.objects.all()
return render(request, 'blog/post_list.html', {
'posts': posts,
'categories': categories,
})
def post_detail(request, year, month, day, slug):
post = get_object_or_404(Post,
status='published',
slug=slug,
publish__year=year,
publish__month=int(month),
publish__day=int(day)
)
# 增加浏览量
post.views += 1
post.save()
# 获取评论
comments = post.comments.filter(active=True, parent=None)
if request.method == 'POST':
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.author = request.user
new_comment.save()
messages.success(request, '评论发表成功!')
return redirect('blog:post_detail', year=year,
month=month, day=day, slug=slug)
else:
comment_form = CommentForm()
return render(request, 'blog/post_detail.html', {
'post': post,
'comments': comments,
'comment_form': comment_form,
})
@login_required
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
messages.success(request, '文章创建成功!')
return redirect(post.get_absolute_url())
else:
form = PostForm()
return render(request, 'blog/post_form.html', {'form': form})
@login_required
def post_edit(request, post_id):
post = get_object_or_404(Post, id=post_id, author=request.user)
if request.method == 'POST':
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save()
messages.success(request, '文章更新成功!')
return redirect(post.get_absolute_url())
else:
form = PostForm(instance=post)
return render(request, 'blog/post_form.html', {'form': form})
六、URL配置
# blog/urls.py
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.post_list, name='post_list'),
path('<int:year>/<int:month>/<int:day>/<slug:slug>/',
views.post_detail, name='post_detail'),
path('create/', views.post_create, name='post_create'),
path('edit/<int:post_id>/', views.post_edit, name='post_edit'),
]
七、模板设计
<!-- blog/templates/blog/base.html -->
<!DOCTYPE html>
<html lang="zh-hans">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}博客{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="{% url 'blog:post_list' %}">博客</a>
<div class="collapse navbar-collapse">
<ul class="navbar-nav ms-auto">
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'blog:post_create' %}">写文章</a>
</li>
<li class="nav-item">
<span class="nav-link">{{ user.username }}</span>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'login' %}">登录</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-4">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{ message.tags }}">
{{ message }}
</div>
{% endfor %}
{% endif %}
{% block content %}
{% endblock %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
八、流程图
九、扩展功能建议
文章功能扩展
- 文章标签系统
- 文章搜索功能
- 文章归档功能
- 相关文章推荐
用户功能扩展
- 用户个人中心
- 用户关注系统
- 消息通知系统
评论功能扩展
- 评论点赞功能
- 评论回复通知
- 评论审核系统
界面优化
- 响应式设计
- 富文本编辑器
- 图片上传功能
十、总结
以上完成了一个基础的博客系统,包括:
- 文章的CRUD操作
- 评论系统的实现
- 用户认证和权限控制
- 分类系统的建立
怎么样今天的内容还满意吗?再次感谢朋友们的观看,关注GZH:凡人的AI工具箱,回复666,送您价值199的AI大礼包。最后,祝您早日实现财务自由,还请给个赞,谢谢!