django与vue3的对接流程详解(上)

Django5 与 Vue3 表单交互(上):后端表单构建与前后端数据传递

Django 的学习,本质上是为了搭建稳定、高效的后端服务,而 Vue3 则是构建灵活、流畅前端界面的利器。当我们将 Django5 的后端能力与 Vue3 的前端优势结合,实现二者间的表单数据交互,就能真正打通"前端输入-后端处理-数据库存储-前端渲染"的完整链路。在前后端交互的流程中,"后端表单构建"与"数据传递"是基础且核心的第一步------前者确保后端能合规接收数据,后者实现前后端数据的顺畅流转。本文作为系列第一篇,将聚焦这两大模块,拆解关键技术细节。

一、Django5 表单:后端数据验证与处理的基石

在前后端分离架构中,Django 表单承担着"数据守门人"的核心角色:它不仅能快速生成表单结构,更能对前端传入的数据进行严格校验,过滤非法值后再传递给后续的数据库存储环节。Django 提供两种核心表单类型,分别适配"非数据库关联"和"数据库关联"场景,覆盖绝大多数业务需求。

1.1 Form 类:非模型关联的灵活表单方案

当表单无需直接操作数据库(如用户登录表单、留言表单)时,Form 类是最优选择------它允许开发者完全自定义字段类型、验证规则,灵活掌控表单逻辑。其使用流程可拆解为"定义表单-处理提交-模板渲染"三步,每一步都有明确的规范和便捷工具。

(1)定义表单结构(forms.py

首先在 Django 应用的 forms.py 文件中,通过继承 forms.Form 类定义表单字段。需指定字段类型(如字符型、邮箱型)、显示标签(label)及基础约束(如最大长度),Django 会自动根据字段类型生成基础验证逻辑(如邮箱格式校验)。

示例:留言表单定义

python 复制代码
# forms.py
from django import forms

class ContactForm(forms.Form):
    # 姓名字段:最大长度100字符,前端显示"姓名"
    name = forms.CharField(label='姓名', max_length=100)
    # 邮箱字段:自动验证邮箱格式(如@符号、域名后缀),前端显示"邮箱"
    email = forms.EmailField(label='邮箱')
    # 留言字段:多行文本输入(通过widget指定),前端显示"留言"
    message = forms.CharField(label='留言', widget=forms.Textarea)
(2)处理表单提交(views.py

表单的提交逻辑需在视图函数中实现,核心是判断请求方法(GET/POST),并完成"数据接收-验证-业务处理"的流程。GET 请求用于返回空表单供前端渲染,POST 请求用于接收用户提交的数据并验证。

示例:留言表单视图处理

python 复制代码
# views.py
from django.shortcuts import render
from .forms import ContactForm

def contact(request):
    # 1. 处理POST请求(用户提交表单)
    if request.method == 'POST':
        # 用前端传入的POST数据初始化表单实例
        form = ContactForm(request.POST)
        # 验证数据是否合规(自动触发字段类型、长度等基础校验)
        if form.is_valid():
            # 提取验证后的"干净数据"(已过滤非法值,如HTML标签)
            name = form.cleaned_data['name']
            email = form.cleaned_data['email']
            message = form.cleaned_data['message']
            
            # 此处可添加业务逻辑:如发送邮件给管理员、记录留言日志
            # 示例:print(f"收到新留言:{name}({email}):{message}")
            
            # 跳转至成功页面,避免刷新重复提交
            return render(request, 'contact_success.html')
    
    # 2. 处理GET请求(用户首次访问页面):返回空表单
    else:
        form = ContactForm()
    
    # 3. 将表单实例传递给模板,供前端渲染
    return render(request, 'contact.html', {'form': form})
(3)模板渲染表单(HTML)

Django 提供便捷的模板标签,无需手动编写大量 HTML 输入框代码。通过 {``{ form.as_p }} 可将表单字段以段落(<p>)形式渲染,自动包含标签(<label>)和输入框(<input>/<textarea>);同时必须添加 {% csrf_token %} 标签,这是 Django 防范跨站请求伪造(CSRF)攻击的关键,缺失会导致表单提交失败。

示例:留言表单模板

html 复制代码
<!-- contact.html -->
<form method="post" action="{% url 'contact' %}">
    {% csrf_token %}  <!-- CSRF防护必备 -->
    {{ form.as_p }}   <!-- 自动渲染所有表单字段(段落形式) -->
    <button type="submit" class="btn">提交留言</button>
</form>

1.2 ModelForm 类:与数据库模型无缝对接的高效方案

若表单需直接操作数据库(如文章发布、用户注册),ModelForm 类能极大简化开发------它会根据数据库模型(Model)自动生成表单字段,甚至支持"一键保存数据到数据库",无需手动编写 create 逻辑,大幅减少重复代码。

(1)定义数据库模型(models.py

首先需在 models.py 中定义对应的数据库模型,明确字段类型和约束,这是 ModelForm 类的"数据基础"。

示例:文章模型定义

python 复制代码
# models.py
from django.db import models

class Article(models.Model):
    # 文章标题:最大长度200字符
    title = models.CharField(max_length=200)
    # 文章内容:长文本类型(无长度限制)
    content = models.TextField()
    # 发布时间:自动填充当前时间(创建时生效,后续不更新)
    pub_date = models.DateTimeField(auto_now_add=True)

    # 可选:定义模型的字符串显示(便于后台管理和调试)
    def __str__(self):
        return self.title
(2)定义 ModelForm 表单(forms.py

通过继承 forms.ModelForm 类,并在内部 Meta 类中指定关联的模型(model)和需生成的表单字段(fields),即可完成表单定义。无需重复声明字段类型------ModelForm 会自动根据模型字段类型映射为表单字段(如模型的 CharField 对应表单的 CharField)。

示例:文章发布表单定义

python 复制代码
# forms.py
from django import forms
from .models import Article  # 导入关联的数据库模型

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article  # 关联的数据库模型
        fields = ['title', 'content']  # 需生成的表单字段(排除自动填充的pub_date)
        labels = {  # 自定义前端显示的字段名称(优化用户体验)
            'title': '文章标题',
            'content': '文章内容'
        }
(3)处理表单提交与数据存储(views.py

ModelForm 的核心优势体现在数据存储环节:当 form.is_valid() 验证通过后,直接调用 form.save() 即可将表单数据自动存入数据库,无需手动创建模型实例并调用 save() 方法。

示例:文章发布视图处理

python 复制代码
# views.py
from django.shortcuts import render, redirect
from .forms import ArticleForm  # 导入ModelForm表单
from .models import Article

def create_article(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            # 一键保存数据到数据库(自动创建Article实例并存储)
            form.save()
            # 跳转至文章列表页,避免刷新重复提交
            return redirect('article_list')  # 需提前定义article_list路由
    else:
        form = ArticleForm()
    
    return render(request, 'create_article.html', {'form': form})

1.3 表单验证:确保数据合规的双重机制

无论使用 Form 还是 ModelForm,Django 都提供了强大的验证机制,覆盖"基础规则"和"复杂业务规则",确保只有合规数据能进入后续流程。

(1)内置验证器:快速实现基础规则

Django 内置了多种开箱即用的验证器,如 MinLengthValidator(最小长度)、MaxLengthValidator(最大长度)、EmailValidator(邮箱格式)等,直接在字段定义中通过 validators 参数引用即可,无需手动编写校验逻辑。

示例:用户表单内置验证

python 复制代码
# forms.py
from django import forms
from django.core.validators import MinLengthValidator, MaxLengthValidator

class UserForm(forms.Form):
    username = forms.CharField(
        label='用户名',
        # 添加"最小5字符、最大20字符"的验证
        validators=[
            MinLengthValidator(5, message='用户名长度不能少于5个字符'),
            MaxLengthValidator(20, message='用户名长度不能超过20个字符')
        ]
    )
    password = forms.CharField(
        label='密码',
        widget=forms.PasswordInput,  # 密码隐藏输入(优化安全性)
        # 添加"最小8字符"的验证
        validators=[MinLengthValidator(8, message='密码长度不能少于8个字符')]
    )
(2)自定义验证方法:应对复杂业务规则

当内置验证器无法满足需求(如"两次密码一致""用户名不重复")时,可在表单类中定义自定义验证方法。分为两种场景:"单字段验证"(针对单个字段的规则)和"全局验证"(针对多个字段的关联规则)。

示例:注册表单自定义验证

python 复制代码
# forms.py
from django import forms
from django.core.exceptions import ValidationError
from .models import User  # 假设存在User模型(用于查询用户名是否重复)

class RegisterForm(forms.Form):
    username = forms.CharField(label='用户名')
    email = forms.EmailField(label='邮箱')
    password1 = forms.CharField(label='密码', widget=forms.PasswordInput)
    password2 = forms.CharField(label='确认密码', widget=forms.PasswordInput)

    # 1. 单字段验证:验证用户名是否已存在(方法名格式:clean_字段名)
    def clean_username(self):
        # 从验证后的干净数据中获取用户名
        username = self.cleaned_data.get('username')
        # 查询数据库:判断用户名是否已存在
        if User.objects.filter(username=username).exists():
            # 抛出验证错误(前端会自动显示该信息)
            raise ValidationError('用户名已被注册,请更换其他用户名')
        return username  # 必须返回该字段的值,否则后续无法获取

    # 2. 全局验证:验证两次密码是否一致(方法名固定为clean)
    def clean(self):
        # 继承父类的clean逻辑,确保基础验证正常执行
        cleaned_data = super().clean()
        # 获取两次密码
        password1 = cleaned_data.get('password1')
        password2 = cleaned_data.get('password2')
        
        # 校验两次密码是否一致(需判断两者均不为空,避免None值比较)
        if password1 and password2 and password1 != password2:
            raise ValidationError('两次输入的密码不一致,请重新输入')

二、Django5 接收 Vue3 表单数据:前后端数据传递的关键链路

在前后端分离架构中,Vue3 无法直接操作数据库,需通过 axios 库 发送 HTTP 请求,将表单数据传递给 Django 后端。根据数据格式(表单格式/JSON 格式)和项目复杂度,Django 提供三种接收方案,分别适配不同场景。

2.1 Vue3 前端:用 axios 发送表单数据

axios 是 Vue3 生态中最常用的 HTTP 客户端,支持异步请求、拦截器等功能,能轻松实现"表单数据发送-响应处理"的流程。核心步骤是"绑定表单数据-阻止默认提交-发送请求-处理结果"。

(1)绑定表单数据与发送请求

通过 Vue3 的 ref 定义响应式表单数据(formData),用 v-model 将输入框与 formData 绑定,确保用户输入实时同步;通过 @submit.prevent 阻止表单默认提交行为(避免页面刷新),转而调用自定义方法 submitForm 发送请求。

示例:Vue3 文章发布表单

vue 复制代码
<template>
  <div class="form-container">
    <h2>添加文章</h2>
    <!-- 阻止默认提交,调用自定义提交方法 -->
    <form @submit.prevent="submitForm">
      <div class="form-group">
        <label for="title">文章标题</label>
        <!-- v-model绑定表单数据:实时同步输入内容 -->
        <input 
          type="text" 
          id="title" 
          v-model="formData.title" 
          required  <!-- 前端基础校验(非空) -->
          placeholder="请输入文章标题"
        >
      </div>
      <div class="form-group">
        <label for="content">文章内容</label>
        <textarea 
          id="content" 
          v-model="formData.content" 
          required 
          placeholder="请输入文章内容"
          rows="6"
        ></textarea>
      </div>
      <button type="submit" class="btn-submit">提交文章</button>
    </form>
  </div>
</template>

<script setup>
// 1. 导入所需工具:ref(响应式数据)、axios(HTTP请求)
import { ref } from 'vue';
import axios from 'axios';  // 需提前安装:npm install axios

// 2. 定义响应式表单数据(初始值为空)
const formData = ref({
  title: '',
  content: ''
});

// 3. 表单提交方法(异步函数,处理HTTP请求)
const submitForm = async () => {
  try {
    // 发送POST请求到Django后端接口(需与Django路由对应)
    const response = await axios.post('/api/articles/', formData.value);
    
    // 请求成功后的处理:如提示用户、重置表单、跳转页面
    alert('文章发布成功!');
    console.log('后端返回数据:', response.data);
    
    // 重置表单(清空输入)
    formData.value = { title: '', content: '' };
    
    // 可选:跳转至文章列表页(需导入useRouter)
    // import { useRouter } from 'vue-router';
    // const router = useRouter();
    // router.push('/articles');
    
  } catch (error) {
    // 请求失败后的处理:如提示错误信息
    alert('文章发布失败,请稍后重试!');
    console.error('请求错误详情:', error);
  }
};
</script>

<style scoped>
/* 简单样式优化,提升用户体验 */
.form-container { max-width: 800px; margin: 20px auto; padding: 0 20px; }
.form-group { margin-bottom: 20px; }
label { display: block; margin-bottom: 8px; font-weight: bold; }
input, textarea { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
.btn-submit { padding: 10px 20px; background: #007bff; color: #fff; border: none; border-radius: 4px; cursor: pointer; }
.btn-submit:hover { background: #0056b3; }
</style>

2.2 Django 后端:三种数据接收方案

Vue3 发送的数据格式不同,Django 的接收方式也不同。核心差异在于"表单格式"(application/x-www-form-urlencoded)和"JSON 格式"(application/json)的解析逻辑,以及是否使用 DRF(Django REST framework)简化开发。

(1)方案1:request.POST 接收表单格式数据

若 Vue3 发送的是传统表单格式数据(需手动设置 Content-Type: application/x-www-form-urlencoded),Django 可直接通过 request.POST 获取字段值------这是最基础的接收方式,适用于简单场景。

示例:Django 接收表单格式数据

python 复制代码
# views.py
from django.http import JsonResponse
from .models import Article

def create_article_api(request):
    # 仅处理POST请求(数据提交)
    if request.method == 'POST':
        # 1. 从request.POST中提取字段值(get方法可避免字段不存在时报错)
        title = request.POST.get('title', '')  # 第二个参数为默认值(空字符串)
        content = request.POST.get('content', '')
        
        # 2. 基础数据校验(非空校验)
        if not title.strip() or not content.strip():
            # 返回JSON格式错误响应(前端可通过response.data获取信息)
            return JsonResponse({
                'status': 'error',
                'message': '文章标题和内容不能为空,请补充完整'
            }, status=400)  # 400状态码表示"请求参数错误"
        
        # 3. 数据存储到数据库
        article = Article.objects.create(
            title=title.strip(),  # 去除前后空格(避免无效数据)
            content=content.strip()
        )
        
        # 4. 返回JSON格式成功响应(包含新创建文章的关键信息)
        return JsonResponse({
            'status': 'success',
            'message': '文章创建成功',
            'data': {
                'article_id': article.id,
                'title': article.title,
                'pub_date': article.pub_date.strftime('%Y-%m-%d %H:%M:%S')  # 格式化时间
            }
        })
    
    # 非POST请求(如GET):返回不支持的方法响应
    return JsonResponse({
        'status': 'error',
        'message': '仅支持POST请求,请使用正确的请求方式'
    }, status=405)  # 405状态码表示"方法不允许"
(2)方案2:request.body 接收 JSON 格式数据

Vue3 用 axios 发送数据时,默认格式为 application/json(无需手动设置 Content-Type),此时 request.POST 无法获取数据,需通过 request.body 处理------request.body 返回二进制数据,需先通过 json.loads 解析为 Python 字典,再提取字段值。

示例:Django 接收 JSON 格式数据

python 复制代码
# views.py
import json  # 导入JSON解析模块
from django.http import JsonResponse
from .models import Article

def create_article_api(request):
    if request.method == 'POST':
        try:
            # 1. 解析JSON数据(request.body是二进制,需先解码为字符串)
            # 捕获JSONDecodeError:处理前端发送的JSON格式错误
            data = json.loads(request.body.decode('utf-8'))
            
            # 2. 提取字段值(与表单格式接收逻辑一致)
            title = data.get('title', '').strip()
            content = data.get('content', '').strip()
            
            # 3. 基础数据校验
            if not title or not content:
                return JsonResponse({
                    'status': 'error',
                    'message': '文章标题和内容不能为空'
                }, status=400)
            
            # 4. 数据存储与成功响应
            article = Article.objects.create(title=title, content=content)
            return JsonResponse({
                'status': 'success',
                'message': '文章创建成功',
                'data': {
                    'article_id': article.id,
                    'title': article.title
                }
            })
        
        # 处理JSON格式错误(如前端发送的不是合法JSON)
        except json.JSONDecodeError:
            return JsonResponse({
                'status': 'error',
                'message': '数据格式错误,请发送合法的JSON数据'
            }, status=400)
    
    # 非POST请求响应
    return JsonResponse({
        'status': 'error',
        'message': '仅支持POST请求'
    }, status=405)
(3)方案3:Django REST framework(DRF)接收数据(复杂场景优选)

对于需要构建完整 API 接口的项目(如支持分页、权限控制、数据序列化),推荐使用 Django REST framework(DRF)------它是 Django 的扩展库,提供了"序列化器""视图集"等工具,可自动处理数据解析、验证、响应,无需手动编写大量重复代码。

步骤1:安装并配置 DRF

首先通过 pip 安装 DRF:

bash 复制代码
pip install djangorestframework

然后在 Django 项目的 settings.py 中添加 DRF 到 INSTALLED_APPS

python 复制代码
# settings.py
INSTALLED_APPS = [
    # ... 其他已安装的应用
    'rest_framework',  # 添加DRF应用
]
步骤2:定义序列化器(serializers.py

序列化器的核心作用是"数据格式转换":将 Django 模型实例转为 JSON 数据(供前端渲染),或把前端传入的 JSON/表单数据转为模型实例(供后端存储),同时自动完成数据验证。

示例:文章序列化器

python 复制代码
# serializers.py
from rest_framework import serializers
from .models import Article

class ArticleSerializer(serializers.ModelSerializer):
    # 内部Meta类指定关联的模型和序列化字段
    class Meta:
        model = Article  # 关联的数据库模型
        fields = ['id', 'title', 'content', 'pub_date']  # 需序列化的字段
        read_only_fields = ['pub_date']  # pub_date为只读字段(自动生成,不允许前端修改)
步骤3:定义视图集(views.py

DRF 的 ModelViewSet 是"全能视图",可自动生成 CRUD 接口(GET 列表/详情、POST 创建、PUT 更新、DELETE 删除),无需手动判断请求方法和解析数据。

示例:文章视图集

python 复制代码
# views.py
from rest_framework import viewsets
from .models import Article
from .serializers import ArticleSerializer

class ArticleViewSet(viewsets.ModelViewSet):
    # 1. 数据源:查询所有文章(可添加过滤条件,如按发布时间排序)
    queryset = Article.objects.all().order_by('-pub_date')  # 倒序:最新文章在前
    # 2. 关联的序列化器:处理数据转换和验证
    serializer_class = ArticleSerializer
步骤4:配置 URL 路由(urls.py

通过 DRF 的 DefaultRouter 注册视图集,自动生成对应的 API 路由。

示例:API 路由配置

python 复制代码
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet

# 1. 创建路由注册器
router = DefaultRouter()
# 2. 注册视图集:路由前缀为'articles',生成的接口路径为/api/articles/
router.register(r'articles', ArticleViewSet)

# 3. 配置URL:将注册器生成的路由包含到项目URL中
urlpatterns = [
    # ... 其他已配置的URL
    path('api/', include(router.urls)),  # API接口根路径:/api/
]
接口使用说明

注册完成后,DRF 会自动生成以下接口,Vue3 可直接请求:

  • GET /api/articles/:获取所有文章列表(支持分页,默认每页10条)
  • POST /api/articles/:创建新文章(自动验证数据,返回创建结果)
  • GET /api/articles/{id}/:获取单篇文章详情({id} 为文章ID)
  • PUT /api/articles/{id}/:更新单篇文章(全量更新)
  • DELETE /api/articles/{id}/:删除单篇文章

Vue3 无需关注数据格式解析------DRF 会自动处理 application/jsonapplication/x-www-form-urlencoded 两种格式,且返回的 JSON 数据包含分页、状态等信息,便于前端处理。

相关推荐
老歌老听老掉牙3 小时前
基于 PyQt5 实现刀具类型选择界面的设计与交互逻辑
python·qt·交互
秦禹辰3 小时前
轻量级开源文件共享系统PicoShare本地部署并实现公网环境文件共享
开发语言·后端·golang
可触的未来,发芽的智生3 小时前
触摸未来2025.10.09:记忆的突围,从64个神经元到人工海马体神经网络
人工智能·python·神经网络·机器学习·架构
Emrys_4 小时前
Redis 为什么这么快?一次彻底搞懂背-后的秘密 🚀
后端·面试
程序员小假4 小时前
我们来说一说 Java 自动装箱与拆箱是什么?
java·后端
随便写写4 小时前
python项目和环境管理工具 UV
后端
摇滚侠4 小时前
Spring Boot 3零基础教程,依赖管理机制,笔记06
spring boot·笔记·后端
❀͜͡傀儡师4 小时前
Spring 前后端通信加密解密
java·后端·spring
川石课堂软件测试4 小时前
什么是BUG,你对BUG的了解有多少?
android·linux·服务器·python·功能测试·bug·安全性测试