每天40分玩转Django:实操博客应用

发布于:2024-12-19 ⋅ 阅读:(11) ⋅ 点赞:(0)

实操博客应用

一、内容概述

模块 重要程度 主要内容
项目初始化 ⭐⭐⭐⭐ 创建项目和应用
模型设计 ⭐⭐⭐⭐⭐ 文章、评论、用户模型
视图实现 ⭐⭐⭐⭐⭐ 增删改查功能
模板开发 ⭐⭐⭐⭐ 页面布局和样式
用户认证 ⭐⭐⭐⭐⭐ 用户登录和权限

二、项目结构

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>

八、流程图

在这里插入图片描述

九、扩展功能建议

  1. 文章功能扩展

    • 文章标签系统
    • 文章搜索功能
    • 文章归档功能
    • 相关文章推荐
  2. 用户功能扩展

    • 用户个人中心
    • 用户关注系统
    • 消息通知系统
  3. 评论功能扩展

    • 评论点赞功能
    • 评论回复通知
    • 评论审核系统
  4. 界面优化

    • 响应式设计
    • 富文本编辑器
    • 图片上传功能

十、总结

以上完成了一个基础的博客系统,包括:

  1. 文章的CRUD操作
  2. 评论系统的实现
  3. 用户认证和权限控制
  4. 分类系统的建立

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