Django与前端框架集成:Vue.js、React的完美配合

目录

  • 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. 最佳实践总结

  1. API设计规范:遵循RESTful原则,保持接口一致性
  2. 错误处理:统一的错误响应格式和前端错误处理机制
  3. 安全性:CSRF保护、XSS防护、输入验证
  4. 性能监控:前后端性能指标收集和分析
  5. 开发体验:热重载、API Mock、调试工具集成

通过以上深度集成方案,Django与Vue.js、React可以实现完美的前后端协作,既保持了Django的强大后端能力,又充分发挥了现代前端框架的优秀用户体验。

相关推荐
p***93031 小时前
使用Django Rest Framework构建API
数据库·django·sqlite
aha-凯心1 小时前
React 中没有 v-model,如何优雅地处理表单输入
前端·javascript·vue.js·react.js
lcc1871 小时前
Vue3 其它Composition API
前端·vue.js
tsumikistep1 小时前
【前后端】Vue 基本使用方式(下)—— 条件渲染、双向绑定、事件绑定
前端·javascript·vue.js
敲敲了个代码1 小时前
一天面了6个前端开发,水平真的令人堪忧啊
前端·javascript·学习·面试·webpack·typescript·前端框架
hellotutu1 小时前
vue2+springboot通过 FormData 手动封装图片数据上传
java·vue.js·spring boot·后端·ui
十五喵1 小时前
游戏助手|游戏攻略|基于SprinBoot+vue的游戏攻略系统小程序(源码+数据库+文档)
vue.js·游戏·小程序
一勺菠萝丶1 小时前
Vue组件状态同步问题:为什么修改了DOM值,提交时还是默认值?
前端·javascript·vue.js
程序媛徐师姐2 小时前
Python基于Django的新闻发布类别自动识别系统【附源码、文档说明】
python·django·新闻发布类别自动识别系统·新闻发布类别自动识别·python新闻类别自动识别·pytho新闻类别识别系统·新闻发布类别识别系统