目录
- Django与前端框架集成:Vue.js、React的完美配合
-
- 引言
- [1. 架构模式选择](#1. 架构模式选择)
-
- [1.1 分离式部署](#1.1 分离式部署)
- [1.2 一体化部署](#1.2 一体化部署)
- [2. Django与Vue.js集成](#2. Django与Vue.js集成)
-
- [2.1 基础配置](#2.1 基础配置)
- [2.2 深度集成方案](#2.2 深度集成方案)
- [2.3 高级功能集成](#2.3 高级功能集成)
- [3. Django与React集成](#3. Django与React集成)
-
- [3.1 项目配置](#3.1 项目配置)
- [3.2 React组件集成](#3.2 React组件集成)
- [3.3 状态管理集成](#3.3 状态管理集成)
- [4. 高级集成特性](#4. 高级集成特性)
-
- [4.1 认证与授权](#4.1 认证与授权)
- [4.2 文件上传与处理](#4.2 文件上传与处理)
- [5. 部署与优化](#5. 部署与优化)
-
- [5.1 生产环境配置](#5.1 生产环境配置)
- [5.2 性能优化](#5.2 性能优化)
- [6. 最佳实践总结](#6. 最佳实践总结)
『宝藏代码胶囊开张啦!』------ 我的 CodeCapsule 来咯!✨写代码不再头疼!我的新站点 CodeCapsule 主打一个 "白菜价"+"量身定制 "!无论是卡脖子的毕设/课设/文献复现 ,需要灵光一现的算法改进 ,还是想给项目加个"外挂",这里都有便宜又好用的代码方案等你发现!低成本,高适配,助你轻松通关!速来围观 👉 CodeCapsule官网
Django与前端框架集成:Vue.js、React的完美配合
引言
在现代Web开发中,前后端分离已成为主流架构模式。Django作为强大的后端框架,与Vue.js、React等现代前端框架的集成能够打造出功能丰富、用户体验优异的Web应用。本文将深入探讨Django如何与这些前端框架完美配合。
1. 架构模式选择
1.1 分离式部署
python
# Django作为纯API后端
# settings.py
INSTALLED_APPS = [
'rest_framework',
'corsheaders',
# ...
]
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
]
}
CORS_ALLOWED_ORIGINS = [
"http://localhost:3000", # React开发服务器
"http://localhost:8080", # Vue开发服务器
]
1.2 一体化部署
python
# Django同时服务前端静态文件
# settings.py
INSTALLED_APPS = [
'django.contrib.staticfiles',
]
STATICFILES_DIRS = [
BASE_DIR / "frontend/dist", # 构建后的前端文件
]
2. Django与Vue.js集成
2.1 基础配置
前端目录结构:
project/
├── backend/ # Django项目
├── frontend/ # Vue.js项目
│ ├── src/
│ ├── public/
│ └── package.json
└── package.json
Django视图配置:
python
# views.py
from django.views.generic import TemplateView
from django.http import JsonResponse
from rest_framework.views import APIView
from rest_framework.response import Response
class VueAppView(TemplateView):
template_name = 'vue_index.html'
class UserAPI(APIView):
def get(self, request):
users = [
{'id': 1, 'name': '张三', 'email': 'zhangsan@example.com'},
{'id': 2, 'name': '李四', 'email': 'lisi@example.com'}
]
return Response(users)
2.2 深度集成方案
Django模板集成Vue组件:
html
<!-- templates/vue_index.html -->
{% load static %}
<!DOCTYPE html>
<html>
<head>
<title>Django + Vue.js</title>
<link rel="stylesheet" href="{% static 'css/app.css' %}">
</head>
<body>
<div id="app">
<navbar :user="userData"></navbar>
<router-view></router-view>
</div>
<script>
window.djangoData = {
user: {{ user_data|safe }},
csrfToken: "{{ csrf_token }}"
};
</script>
<script src="{% static 'js/chunk-vendors.js' %}"></script>
<script src="{% static 'js/app.js' %}"></script>
</body>
</html>
Vue组件调用Django API:
javascript
// src/services/api.js
import axios from 'axios';
const apiClient = axios.create({
baseURL: process.env.VUE_APP_API_URL || '/api',
headers: {
'X-CSRFToken': getCSRFToken(),
'Content-Type': 'application/json'
}
});
function getCSRFToken() {
return document.querySelector('[name=csrfmiddlewaretoken]')?.value ||
window.djangoData?.csrfToken;
}
export default {
async getUsers() {
const response = await apiClient.get('/users/');
return response.data;
},
async createUser(userData) {
const response = await apiClient.post('/users/', userData);
return response.data;
}
};
2.3 高级功能集成
实时数据更新:
python
# consumers.py - Django Channels
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class UserConsumer(AsyncWebsocketConsumer):
async def connect(self):
await self.channel_layer.group_add("users", self.channel_name)
await self.accept()
async def user_updated(self, event):
await self.send(text_data=json.dumps(event["data"]))
javascript
// Vue组件中使用WebSocket
// src/components/UserList.vue
<template>
<div>
<div v-for="user in users" :key="user.id" class="user-item">
{{ user.name }} - {{ user.email }}
</div>
</div>
</template>
<script>
import { ref, onMounted, onUnmounted } from 'vue';
import api from '../services/api';
export default {
setup() {
const users = ref([]);
let socket = null;
const loadUsers = async () => {
users.value = await api.getUsers();
};
const setupWebSocket = () => {
socket = new WebSocket('ws://localhost:8000/ws/users/');
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
// 更新用户列表
const index = users.value.findIndex(u => u.id === data.id);
if (index !== -1) {
users.value.splice(index, 1, data);
} else {
users.value.push(data);
}
};
};
onMounted(() => {
loadUsers();
setupWebSocket();
});
onUnmounted(() => {
if (socket) socket.close();
});
return { users };
}
};
</script>
3. Django与React集成
3.1 项目配置
Django REST Framework序列化器:
python
# 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', 'first_name', 'last_name']
read_only_fields = ['id']
class UserProfileSerializer(serializers.Serializer):
user = UserSerializer()
avatar = serializers.ImageField()
bio = serializers.CharField()
React API服务:
javascript
// src/services/djangoAPI.js
import axios from 'axios';
class DjangoAPI {
constructor() {
this.client = axios.create({
baseURL: process.env.REACT_APP_API_BASE_URL || 'http://localhost:8000/api',
timeout: 10000,
});
this.setupInterceptors();
}
setupInterceptors() {
this.client.interceptors.request.use(
(config) => {
const token = this.getCSRFToken();
if (token) {
config.headers['X-CSRFToken'] = token;
}
return config;
},
(error) => Promise.reject(error)
);
this.client.interceptors.response.use(
(response) => response,
(error) => {
if (error.response?.status === 403) {
// CSRF token失效,重新获取
this.refreshCSRFToken();
}
return Promise.reject(error);
}
);
}
getCSRFToken() {
// 从cookie或meta标签获取CSRF token
const name = 'csrftoken';
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
return document.querySelector('[name=csrfmiddlewaretoken]')?.value;
}
async refreshCSRFToken() {
await this.client.get('/auth/csrf/');
}
// 用户相关API
async getUsers(params = {}) {
const response = await this.client.get('/users/', { params });
return response.data;
}
async createUser(userData) {
const response = await this.client.post('/users/', userData);
return response.data;
}
async uploadFile(file, onProgress = null) {
const formData = new FormData();
formData.append('file', file);
const config = onProgress ? {
onUploadProgress: (progressEvent) => {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
onProgress(percent);
}
} : {};
const response = await this.client.post('/upload/', formData, config);
return response.data;
}
}
export default new DjangoAPI();
3.2 React组件集成
用户管理组件:
jsx
// src/components/UserManager.jsx
import React, { useState, useEffect } from 'react';
import { Table, Button, Modal, Form, Input, message } from 'antd';
import djangoAPI from '../services/djangoAPI';
const UserManager = () => {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(false);
const [modalVisible, setModalVisible] = useState(false);
const [form] = Form.useForm();
const loadUsers = async () => {
setLoading(true);
try {
const userData = await djangoAPI.getUsers();
setUsers(userData);
} catch (error) {
message.error('加载用户数据失败');
} finally {
setLoading(false);
}
};
const handleCreateUser = async (values) => {
try {
await djangoAPI.createUser(values);
message.success('用户创建成功');
setModalVisible(false);
form.resetFields();
loadUsers(); // 重新加载数据
} catch (error) {
message.error('创建用户失败');
}
};
useEffect(() => {
loadUsers();
}, []);
const columns = [
{
title: 'ID',
dataIndex: 'id',
key: 'id',
},
{
title: '用户名',
dataIndex: 'username',
key: 'username',
},
{
title: '邮箱',
dataIndex: 'email',
key: 'email',
},
{
title: '操作',
key: 'actions',
render: (_, record) => (
<Button type="link" onClick={() => handleEdit(record)}>
编辑
</Button>
),
},
];
return (
<div>
<div style={{ marginBottom: 16 }}>
<Button
type="primary"
onClick={() => setModalVisible(true)}
>
添加用户
</Button>
</div>
<Table
columns={columns}
dataSource={users}
rowKey="id"
loading={loading}
/>
<Modal
title="创建用户"
open={modalVisible}
onCancel={() => setModalVisible(false)}
footer={null}
>
<Form
form={form}
layout="vertical"
onFinish={handleCreateUser}
>
<Form.Item
label="用户名"
name="username"
rules={[{ required: true, message: '请输入用户名' }]}
>
<Input />
</Form.Item>
<Form.Item
label="邮箱"
name="email"
rules={[
{ required: true, message: '请输入邮箱' },
{ type: 'email', message: '邮箱格式不正确' }
]}
>
<Input />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">
创建
</Button>
</Form.Item>
</Form>
</Modal>
</div>
);
};
export default UserManager;
3.3 状态管理集成
Redux与Django集成:
javascript
// src/store/userSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import djangoAPI from '../services/djangoAPI';
export const fetchUsers = createAsyncThunk(
'users/fetchUsers',
async (params, { rejectWithValue }) => {
try {
return await djangoAPI.getUsers(params);
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
export const createUser = createAsyncThunk(
'users/createUser',
async (userData, { rejectWithValue }) => {
try {
return await djangoAPI.createUser(userData);
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
const userSlice = createSlice({
name: 'users',
initialState: {
items: [],
loading: false,
error: null
},
reducers: {
clearError: (state) => {
state.error = null;
}
},
extraReducers: (builder) => {
builder
.addCase(fetchUsers.pending, (state) => {
state.loading = true;
state.error = null;
})
.addCase(fetchUsers.fulfilled, (state, action) => {
state.loading = false;
state.items = action.payload;
})
.addCase(fetchUsers.rejected, (state, action) => {
state.loading = false;
state.error = action.payload;
})
.addCase(createUser.fulfilled, (state, action) => {
state.items.push(action.payload);
});
}
});
export const { clearError } = userSlice.actions;
export default userSlice.reducer;
4. 高级集成特性
4.1 认证与授权
Django REST Framework认证:
python
# authentication.py
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework_simplejwt.authentication import JWTAuthentication
class CsrfExemptSessionAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return # 禁用CSRF检查,适用于移动端
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
React中的认证处理:
javascript
// src/hooks/useAuth.js
import { useState, useEffect, createContext, useContext } from 'react';
import djangoAPI from '../services/djangoAPI';
const AuthContext = createContext();
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth必须在AuthProvider内使用');
}
return context;
};
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
checkAuth();
}, []);
const checkAuth = async () => {
try {
const userData = await djangoAPI.getCurrentUser();
setUser(userData);
} catch (error) {
setUser(null);
} finally {
setLoading(false);
}
};
const login = async (credentials) => {
try {
const userData = await djangoAPI.login(credentials);
setUser(userData);
return { success: true };
} catch (error) {
return {
success: false,
error: error.response?.data || '登录失败'
};
}
};
const logout = async () => {
await djangoAPI.logout();
setUser(null);
};
const value = {
user,
loading,
login,
logout,
isAuthenticated: !!user
};
return (
<AuthContext.Provider value={value}>
{children}
</AuthContext.Provider>
);
};
4.2 文件上传与处理
Django文件处理视图:
python
# views.py
from rest_framework.parsers import MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework.views import APIView
from django.core.files.storage import default_storage
class FileUploadView(APIView):
parser_classes = [MultiPartParser, FormParser]
def post(self, request, format=None):
file_obj = request.FILES['file']
# 保存文件
file_path = default_storage.save(f'uploads/{file_obj.name}', file_obj)
file_url = default_storage.url(file_path)
return Response({
'url': file_url,
'name': file_obj.name,
'size': file_obj.size
})
React文件上传组件:
jsx
// src/components/FileUpload.jsx
import React, { useState } from 'react';
import { Upload, Button, message, Progress } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import djangoAPI from '../services/djangoAPI';
const FileUpload = () => {
const [uploading, setUploading] = useState(false);
const [progress, setProgress] = useState(0);
const handleUpload = async (file) => {
setUploading(true);
setProgress(0);
try {
await djangoAPI.uploadFile(file, (percent) => {
setProgress(percent);
});
message.success('文件上传成功');
} catch (error) {
message.error('文件上传失败');
} finally {
setUploading(false);
setProgress(0);
}
};
return (
<div>
<Upload
customRequest={({ file }) => handleUpload(file)}
showUploadList={false}
disabled={uploading}
>
<Button icon={<UploadOutlined />} disabled={uploading}>
选择文件
</Button>
</Upload>
{uploading && (
<Progress
percent={progress}
style={{ marginTop: 16 }}
/>
)}
</div>
);
};
export default FileUpload;
5. 部署与优化
5.1 生产环境配置
Django静态文件配置:
python
# settings.py
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
# 收集前端构建文件
STATICFILES_DIRS = [
BASE_DIR / 'frontend/build/static', # React
BASE_DIR / 'frontend/dist/static', # Vue
]
# WhiteNoise配置
MIDDLEWARE = [
'whitenoise.middleware.WhiteNoiseMiddleware',
# ...
]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
前端构建配置:
javascript
// vue.config.js
module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/static/'
: '/',
outputDir: '../backend/static/frontend',
indexPath: '../../templates/vue_index.html'
};
// package.json
{
"scripts": {
"build": "vue-cli-service build",
"build:django": "npm run build && cp -r dist/* ../backend/static/frontend/"
}
}
5.2 性能优化
Django数据库优化:
python
# views.py
class OptimizedUserAPI(APIView):
def get(self, request):
# 使用select_related和prefetch_related优化查询
users = User.objects.select_related('profile').prefetch_related(
'groups', 'user_permissions'
)[:100] # 分页
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
前端代码分割:
javascript
// React懒加载
const UserManager = lazy(() => import('./components/UserManager'));
const FileUpload = lazy(() => import('./components/FileUpload'));
// Vue异步组件
const AsyncComponent = () => ({
component: import('./components/AsyncComponent.vue'),
loading: LoadingComponent,
error: ErrorComponent,
timeout: 3000
});
6. 最佳实践总结
- API设计规范:遵循RESTful原则,保持接口一致性
- 错误处理:统一的错误响应格式和前端错误处理机制
- 安全性:CSRF保护、XSS防护、输入验证
- 性能监控:前后端性能指标收集和分析
- 开发体验:热重载、API Mock、调试工具集成
通过以上深度集成方案,Django与Vue.js、React可以实现完美的前后端协作,既保持了Django的强大后端能力,又充分发挥了现代前端框架的优秀用户体验。