基于 Vue + Django + MySQL 实现个人博客/CMS系统

发布于:2025-04-06 ⋅ 阅读:(13) ⋅ 点赞:(0)

目录

1. 环境搭建与项目初始化

后端 (Django)

2. 数据库模型设计

用户认证模型 (Django Auth)

文章模型 (models.py)

全文索引优化

3. 后端API开发 (Django REST Framework)

用户注册/登录

文章发布与搜索

4. 前端实现 (Vue 3)

项目初始化

核心功能实现

5. 访问统计实现

后端中间件记录PV/UV

6. 部署与优化

关键问题解决


1. 环境搭建与项目初始化

后端 (Django)

  1. 创建Django项目

    django-admin startproject blog_backend
    cd blog_backend
    python manage.py startapp blog
  2. 安装依赖

    pip install django djangorestframework django-cors-headers djangorestframework-simplejwt mysqlclient
  3. 配置MySQL数据库
    修改 settings.py

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'blog_db',
            'USER': 'root',
            'PASSWORD': 'your_password',
            'HOST': 'localhost',
            'PORT': '3306',
        }
    }
  4. 配置DRF和JWT
    修改 settings.py

INSTALLED_APPS = [
    # ...
    'rest_framework',
    'corsheaders',
    'blog',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    # ...
]

CORS_ALLOW_ALL_ORIGINS = True  # 开发阶段允许所有跨域

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}

    2. 数据库模型设计

    用户认证模型 (Django Auth)

    直接使用Django内置的 User 模型,无需额外设计。

    文章模型 (models.py)

    from django.db import models
    from django.contrib.auth.models import User
    
    class Article(models.Model):
        title = models.CharField(max_length=200)
        content = models.TextField()  # 存储Markdown或HTML内容
        author = models.ForeignKey(User, on_delete=models.CASCADE)
        category = models.CharField(max_length=50)
        tags = models.CharField(max_length=100)  # 逗号分隔的标签,如 "Python,Web"
        created_at = models.DateTimeField(auto_now_add=True)
        updated_at = models.DateTimeField(auto_now=True)
    
        def __str__(self):
            return self.title
    
    class Comment(models.Model):
        article = models.ForeignKey(Article, on_delete=models.CASCADE)
        user = models.ForeignKey(User, on_delete=models.CASCADE)
        content = models.TextField()
        parent_comment = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True)  # 树形评论
        created_at = models.DateTimeField(auto_now_add=True)

    全文索引优化

    在MySQL中为 Article 表添加全文索引:

    ALTER TABLE blog_article ADD FULLTEXT(title, content);

    3. 后端API开发 (Django REST Framework)

    用户注册/登录

    1. 序列化器 (serializers.py)

      from rest_framework import serializers
      from django.contrib.auth.models import User
      
      class UserSerializer(serializers.ModelSerializer):
          class Meta:
              model = User
              fields = ('id', 'username', 'email', 'password')
              extra_kwargs = {'password': {'write_only': True}}
      
          def create(self, validated_data):
              user = User.objects.create_user(**validated_data)
              return user
    2. 视图 (views.py)

      from rest_framework.views import APIView
      from rest_framework.response import Response
      from rest_framework_simplejwt.tokens import RefreshToken
      
      class RegisterView(APIView):
          def post(self, request):
              serializer = UserSerializer(data=request.data)
              if serializer.is_valid():
                  user = serializer.save()
                  refresh = RefreshToken.for_user(user)
                  return Response({
                      'refresh': str(refresh),
                      'access': str(refresh.access_token),
                  })
              return Response(serializer.errors, status=400)

    文章发布与搜索

    1. 文章序列化器

      class ArticleSerializer(serializers.ModelSerializer):
          class Meta:
              model = Article
              fields = '__all__'
    2. 文章搜索接口
      使用Django ORM的全文搜索:

      class ArticleSearchView(APIView):
          def get(self, request):
              query = request.query_params.get('q', '')
              # MySQL全文搜索语法
              articles = Article.objects.raw(
                  "SELECT * FROM blog_article WHERE MATCH(title, content) AGAINST (%s)",
                  [query]
              )
              serializer = ArticleSerializer(articles, many=True)
              return Response(serializer.data)

    4. 前端实现 (Vue 3)

    项目初始化

    npm create vue@latest blog_frontend
    cd blog_frontend
    npm install axios vue-router vuex quill @vueuse/core

    核心功能实现

    1. Markdown渲染
      使用 marked 或 vue-markdown 库:

      <template>
        <div v-html="compiledMarkdown"></div>
      </template>
      
      <script setup>
      import { marked } from 'marked'
      const compiledMarkdown = marked(props.content)
      </script>
    2. 富文本编辑器集成 (Quill)

      <template>
        <div ref="editor"></div>
      </template>
      
      <script setup>
      import Quill from 'quill'
      import 'quill/dist/quill.snow.css'
      
      const editor = ref(null)
      onMounted(() => {
        const quill = new Quill(editor.value, {
          theme: 'snow',
          modules: { toolbar: true }
        })
      })
      </script>
    3. 动态路由SEO优化
      使用 vue-router 和预渲染插件 prerender-spa-plugin

      // vue.config.js
      const PrerenderSPAPlugin = require('prerender-spa-plugin')
      
      module.exports = {
        configureWebpack: {
          plugins: [
            new PrerenderSPAPlugin({
              staticDir: path.join(__dirname, 'dist'),
              routes: ['/', '/articles', '/about'],  // 预渲染的路由
            })
          ]
        }
      }

    5. 访问统计实现

    后端中间件记录PV/UV

    1. 创建访问记录模型

      class AccessLog(models.Model):
          ip = models.CharField(max_length=50)
          path = models.CharField(max_length=200)
          user = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
          created_at = models.DateTimeField(auto_now_add=True)
    2. 中间件统计访问量

      class AccessLogMiddleware:
          def __init__(self, get_response):
              self.get_response = get_response
      
          def __call__(self, request):
              response = self.get_response(request)
              AccessLog.objects.create(
                  ip=request.META.get('REMOTE_ADDR'),
                  path=request.path,
                  user=request.user if request.user.is_authenticated else None
              )
              return response

    6. 部署与优化

    1. MySQL全文索引查询优化
      确保MySQL版本 >= 5.6,并配置索引:

      CREATE FULLTEXT INDEX ft_idx ON blog_article(title, content);
    2. Nginx配置反向代理

      server {
          listen 80;
          server_name your_domain.com;
      
          location /api {
              proxy_pass http://localhost:8000;
              proxy_set_header Host $host;
          }
      
          location / {
              root /path/to/vue/dist;
              try_files $uri $uri/ /index.html;
          }
      }
    3. 性能优化

      • 使用 django-debug-toolbar 分析查询

      • Vue路由懒加载:

        const routes = [
          { path: '/article/:id', component: () => import('./views/ArticleDetail.vue') }
        ]

    关键问题解决

    1. 跨域配置
      使用 django-cors-headers,确保前端能访问后端API。

    2. 树形评论渲染
      前端递归组件实现:

      <template>
        <div v-for="comment in comments" :key="comment.id">
          <div>{{ comment.content }}</div>
          <CommentTree v-if="comment.replies" :comments="comment.replies"/>
        </div>
      </template>
    3. JWT Token自动刷新
      使用Axios拦截器:

      axios.interceptors.response.use(response => response, error => {
        if (error.response.status === 401) {
          return refreshToken().then(() => {
            return axios(error.config)
          })
        }
        return Promise.reject(error)
      })

    通过以上步骤,你可以逐步搭建一个功能完整的博客系统。建议先从基础功能(如文章发布)开始,逐步迭代添加评论、搜索等模块。


    网站公告

    今日签到

    点亮在社区的每一天
    去签到