Django - 內容管理系統 (CMS)
內容管理系統 (Content Management System, CMS) 是一種幫助用戶創建、編輯、組織和發布內容的工具。Django 的靈活性和可擴展性,使其成為構建 CMS 的理想框架。本節課程將帶領你設計並實現一個簡單但功能完整的 CMS 系統,支援內容分類、內容編輯和使用者角色管理等功能。
課程目標
- 瞭解 CMS 的基本概念與設計原則。
- 使用 Django 構建一個簡單的 CMS 系統,包括文章、分類與標籤管理。
- 實現內容的版本控制與權限管理功能。
課程內容
1. CMS 基本結構設計
功能需求
- 管理內容(文章/頁面)。
- 支持分類與標籤系統。
- 提供簡單的權限控制(如作者、編輯者、管理員)。
- 支持內容狀態(如草稿、已發布)。
數據模型設計
在 models.py
中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
class Tag(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
def __str__(self):
return self.name
class Post(models.Model):
STATUS_CHOICES = [
('draft', '草稿'),
('published', '已發布'),
]
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, blank=True)
tags = models.ManyToManyField(Tag, blank=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
published_at = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.title
2. 設計管理後台界面
註冊模型
在 admin.py
中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from django.contrib import admin
from .models import Category, Tag, Post
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'created_at')
prepopulated_fields = {'slug': ('name',)}
@admin.register(Tag)
class TagAdmin(admin.ModelAdmin):
list_display = ('name',)
prepopulated_fields = {'slug': ('name',)}
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'status', 'created_at', 'published_at')
list_filter = ('status', 'created_at', 'author')
search_fields = ('title', 'content')
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',)
date_hierarchy = 'published_at'
ordering = ('-published_at',)
3. 添加內容版本控制
安裝 Django Simple History
1
pip install django-simple-history
修改模型以支持版本控制
在 models.py
中:
1
2
3
4
5
from simple_history.models import HistoricalRecords
class Post(models.Model):
# 其他字段
history = HistoricalRecords()
在 settings.py
中啟用版本控制:
1
2
INSTALLED_APPS += ['simple_history']
MIDDLEWARE += ['simple_history.middleware.HistoryRequestMiddleware']
執行遷移:
1
2
python manage.py makemigrations
python manage.py migrate
現在,後台會記錄每次內容變更的歷史版本。
4. 權限管理與工作流程
角色與權限
- 作者:可以創建和編輯自己的文章,但無法發布。
- 編輯者:可以編輯所有文章並負責發布。
- 管理員:具有最高管理權限。
在 admin.py
中自定義權限檢查:
1
2
3
4
5
6
7
8
9
10
11
class PostAdmin(admin.ModelAdmin):
def get_queryset(self, request):
qs = super().get_queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(author=request.user)
def save_model(self, request, obj, form, change):
if not change or not obj.author_id:
obj.author = request.user
super().save_model(request, obj, form, change)
5. 添加 API 支持
安裝 Django REST Framework
1
pip install djangorestframework
創建 API
在 views.py
中:
1
2
3
4
5
6
7
from rest_framework import viewsets
from .models import Post, Category, Tag
from .serializers import PostSerializer, CategorySerializer, TagSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.filter(status='published')
serializer_class = PostSerializer
在 serializers.py
中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from rest_framework import serializers
from .models import Post, Category, Tag
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = '__all__'
設定路由
在 urls.py
中:
1
2
3
4
5
6
7
8
9
from rest_framework.routers import DefaultRouter
from .views import PostViewSet, CategoryViewSet, TagViewSet
router = DefaultRouter()
router.register(r'posts', PostViewSet)
router.register(r'categories', CategoryViewSet)
router.register(r'tags', TagViewSet)
urlpatterns += router.urls
課堂練習
- 為 CMS 系統中的每個模型設計管理後台界面。
- 添加版本控制功能,並在後台測試歷史版本的查看與恢復功能。
- 為文章管理功能實現簡單的 API,支持查詢發布的內容。
作業
- 實現文章的審核流程,支持作者提交草稿後由編輯者審核並發布。
- 添加 API 身份驗證功能,僅允許已認證的使用者存取。
- 整合 API 與前端,實現一個簡單的前後端分離的 CMS 頁面。
本文章以 CC BY 4.0 授權