在前后端分离开发日益普及的今天,Django 作为成熟的后端框架,Vue3 作为灵活高效的前端框架,二者的结合成为开发 Web 应用的热门选择。本文将基于专业课件内容,从 Django5 表单基础操作、接收 Vue3 表单数据、数据库交互,到综合案例实战,全方位解析二者的表单交互逻辑,附带完整代码示例与详细说明,助力开发者快速上手。

一、Django5 表单基础:从 Form 到 ModelForm

Django 提供了两种核心表单类 ——Form(无模型关联)和ModelForm(与模型绑定),可快速实现表单创建、验证与数据处理。

1.1 Form 类:处理无模型关联的表单

当表单无需与数据库模型直接绑定(如登录表单、留言表单)时,使用Form类最为合适。以下以 “留言表单” 为例,展示完整实现流程。

步骤 1:定义 Form 类(forms.py)

在 Django 应用目录下创建forms.py,定义表单字段与验证规则:

# forms.py
from django import forms

class ContactForm(forms.Form):
    # 姓名:最大长度100字符,自定义标签
    name = forms.CharField(label='姓名', max_length=100)
    # 邮箱:自动验证邮箱格式
    email = forms.EmailField(label='邮箱')
    # 留言:使用文本域(Textarea)组件
    message = forms.CharField(label='留言', widget=forms.Textarea)
步骤 2:视图处理表单逻辑(views.py)

在视图中判断请求方法,处理表单提交与验证:

# views.py
from django.shortcuts import render
from .forms import ContactForm

def contact(request):
    # 1. 处理POST请求(表单提交)
    if request.method == 'POST':
        # 将POST数据传入Form类,创建表单实例
        form = ContactForm(request.POST)
        # 验证表单数据是否合法
        if form.is_valid():
            # 从验证后的字典中获取数据(cleaned_data)
            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()  # 创建空表单实例
    
    # 渲染表单页面,传递表单实例到模板
    return render(request, 'contact.html', {'form': form})
步骤 3:模板渲染表单(templates/contact.html)

使用 Django 模板语法快速渲染表单,无需手动编写 HTML 输入框:

<!-- contact.html -->
<form method="post">
    <!-- 必加:Django CSRF 防护令牌 -->
    {% csrf_token %}
    <!-- 以段落(<p>)形式渲染所有表单字段 -->
    {{ form.as_p }}
    <button type="submit">提交留言</button>
</form>

form.as_p会自动为每个字段生成<p>标签包裹的 HTML(包含标签、输入框、错误提示),也可使用form.as_table(表格形式)或form.as_ul(列表形式)。

1.2 ModelForm 类:绑定数据库模型

当表单需要直接操作数据库(如创建文章、添加商品)时,ModelForm可自动生成表单字段,并简化数据存储逻辑(无需手动调用save()以外的方法)。以下以 “文章发布” 为例实现。

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

首先创建与表单关联的模型:

# models.py
from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=200, verbose_name='文章标题')
    content = models.TextField(verbose_name='文章内容')
    pub_date = models.DateTimeField(auto_now_add=True, verbose_name='发布时间')
    # auto_now_add=True:创建时自动填充当前时间

    class Meta:
        verbose_name = '文章'
        verbose_name_plural = '文章'  # 复数形式(避免后台显示为“article”)
步骤 2:定义 ModelForm 类(forms.py)

通过Meta类指定关联的模型与字段:

# forms.py
from django import forms
from .models import Article

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article  # 关联的模型
        fields = ['title', 'content']  # 表单需包含的模型字段
        labels = {  # 自定义表单字段标签(替代模型的verbose_name)
            'title': '标题',
            'content': '内容'
        }
        # 可选:自定义字段组件(如为content添加样式)
        widgets = {
            'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 10})
        }
步骤 3:视图处理 ModelForm(views.py)

ModelFormsave()方法可直接将验证后的数据存储到数据库:

# views.py
from django.shortcuts import render, redirect
from .forms import ArticleForm

def create_article(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            # 直接保存到数据库(无需手动创建模型实例)
            form.save()
            # 跳转至文章列表页(需提前定义article_list视图与URL)
            return redirect('article_list')
    else:
        form = ArticleForm()
    
    return render(request, 'create_article.html', {'form': form})

1.3 表单验证:内置与自定义结合

Django 表单验证分为 “内置验证器”(快速实现基础规则)和 “自定义验证方法”(处理复杂业务逻辑),确保数据合法性。

1.3.1 内置验证器

直接在表单字段中添加validators参数,示例:

# 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,  # 密码隐藏输入
        validators=[MinLengthValidator(8, message='密码长度不能少于8个字符')]
    )
1.3.2 自定义验证方法

当内置验证器无法满足需求(如 “两次密码一致”“用户名不重复”)时,需定义自定义验证方法:

# 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')
        
        # 验证两次密码是否一致
        if password1 and password2 and password1 != password2:
            raise ValidationError('两次输入的密码不一致')  # 全局错误提示
        return cleaned_data

二、Django5 接收 Vue3 表单数据:axios 与 JSON 交互

前后端分离架构中,Vue3 通过axios发送表单数据,Django5 需接收 JSON 或表单格式数据,并存储到 MySQL 数据库。

2.1 Vue3 前端:用 axios 发送数据

Vue3 中使用axios发送 POST 请求,需注意数据格式(表单格式或 JSON 格式)与 CSRF 防护。

示例:Vue3 文章提交表单
<!-- ArticleForm.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
          class="form-control"
        >
      </div>
      <div class="form-group">
        <label for="content">内容</label>
        <textarea 
          id="content" 
          v-model="formData.content" 
          required
          class="form-control"
          rows="8"
        ></textarea>
      </div>
      <button type="submit" class="btn btn-primary">提交</button>
    </form>
  </div>
</template>

<script setup>
// 1. 导入依赖
import { ref } from 'vue';
import axios from 'axios';

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

// 3. 提交表单方法(异步)
const submitForm = async () => {
  try {
    // 发送POST请求:两种数据格式可选
    const response = await axios.post(
      '/api/articles/',  // Django后端接口URL
      formData.value,    // 发送的数据(默认JSON格式)
      // 可选:若需发送表单格式数据,添加以下配置
      // {
      //   headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      //   transformRequest: [(data) => Object.entries(data).join('&')]
      // }
    );
    
    // 提交成功后的处理(如提示、跳转)
    alert('文章创建成功!');
    console.log('响应数据:', response.data);
    // 跳转至文章列表页(需导入useRouter)
    // router.push('/articles');
  } catch (error) {
    // 捕获错误(如后端验证失败)
    alert('提交失败:' + (error.response?.data?.message || '未知错误'));
    console.error('错误详情:', error);
  }
};
</script>

<style scoped>
.form-container { max-width: 800px; margin: 20px auto; padding: 0 20px; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
</style>

2.2 Django5 后端:接收不同格式数据

Django 接收数据的方式取决于 Vue3 发送的格式(JSON 或表单格式),以下分两种场景实现。

2.2.1 接收 JSON 格式数据(推荐)

当 Vue3 发送Content-Type: application/json时,Django 需通过request.body解析 JSON 数据:

# views.py
import json
from django.http import JsonResponse
from .models import Article

def create_article_api(request):
    # 仅允许POST请求
    if request.method != 'POST':
        return JsonResponse({
            'status': 'error',
            'message': '仅支持POST请求'
        }, status=405)  # 405:方法不允许
    
    try:
        # 解析JSON数据(request.body是字节流,需先解码)
        data = json.loads(request.body.decode('utf-8'))
        # 提取字段并验证
        title = data.get('title')
        content = data.get('content')
        
        if not title or not content:
            return JsonResponse({
                'status': 'error',
                'message': '标题和内容不能为空'
            }, status=400)  # 400:请求参数错误
        
        # 存储到数据库
        article = Article.objects.create(title=title, content=content)
        
        # 返回成功响应(包含新创建文章的信息)
        return JsonResponse({
            'status': 'success',
            'message': '文章创建成功',
            'data': {
                'id': article.id,
                'title': article.title,
                'pub_date': article.pub_date.strftime('%Y-%m-%d %H:%M:%S')  # 格式化时间
            }
        }, status=201)  # 201:创建成功
    
    # 捕获JSON解析错误
    except json.JSONDecodeError:
        return JsonResponse({
            'status': 'error',
            'message': '数据格式错误(需JSON格式)'
        }, status=400)
    
    # 捕获其他异常(如数据库错误)
    except Exception as e:
        return JsonResponse({
            'status': 'error',
            'message': f'服务器错误:{str(e)}'
        }, status=500)  # 500:服务器内部错误
2.2.2 接收表单格式数据

当 Vue3 发送Content-Type: application/x-www-form-urlencoded时,Django 可直接通过request.POST获取数据:

# views.py(表单格式版)
from django.http import JsonResponse
from .models import Article

def create_article_api(request):
    if request.method != 'POST':
        return JsonResponse({'status': 'error', 'message': '仅支持POST请求'}, status=405)
    
    # 从request.POST获取表单数据
    title = request.POST.get('title')
    content = request.POST.get('content')
    
    if not title or not content:
        return JsonResponse({'status': 'error', 'message': '标题和内容不能为空'}, status=400)
    
    try:
        article = Article.objects.create(title=title, content=content)
        return JsonResponse({
            'status': 'success',
            'message': '文章创建成功',
            'data': {'id': article.id, 'title': article.title}
        }, status=201)
    except Exception as e:
        return JsonResponse({'status': 'error', 'message': str(e)}, status=500)

三、Django5 查库与 Vue3 渲染:JSON 数据响应

Django 从数据库查询数据后,以 JSON 格式响应给 Vue3,Vue3 接收数据并渲染到页面。

3.1 Django5 后端:查询数据并返回 JSON

3.1.1 原生 Django 实现(无 DRF):
# views.py
from django.http import JsonResponse
from django.utils import timezone
from datetime import timedelta
from .models import Article

def get_articles(request):
    # 1. 数据库查询(示例:获取近7天的文章,按发布时间倒序)
    seven_days_ago = timezone.now() - timedelta(days=7)
    articles = Article.objects.filter(
        pub_date__gte=seven_days_ago  # 发布时间≥7天前
    ).order_by('-pub_date')  # 按发布时间倒序(最新的在前)
    
    # 2. 转换数据格式(QuerySet→列表字典,便于JSON序列化)
    articles_list = []
    for article in articles:
        articles_list.append({
            'id': article.id,
            'title': article.title,
            'content': article.content[:100] + '...' if len(article.content) > 100 else article.content,  # 内容截取
            'pub_date': article.pub_date.strftime('%Y-%m-%d %H:%M')
        })
    
    # 3. 返回JSON响应
    return JsonResponse({
        'status': 'success',
        'data': articles_list,
        'count': len(articles_list)  # 附加数据总数
    })
3.1.2 DRF 实现(自动序列化)

若已使用 DRF,ListAPIView可自动查询并序列化数据:

# views.py
from rest_framework import generics
from .models import Article
from .serializers import ArticleSerializer

class ArticleListView(generics.ListAPIView):
    # 自定义查询逻辑(如仅返回近7天的文章)
    def get_queryset(self):
        seven_days_ago = timezone.now() - timedelta(days=7)
        return Article.objects.filter(pub_date__gte=seven_days_ago).order_by('-pub_date')
    
    serializer_class = ArticleSerializer  # 自动序列化

3.2 Vue3 前端:接收并渲染数据

Vue3 通过axios获取 Django 响应的 JSON 数据,结合v-for渲染列表,并处理加载状态与错误。

示例:Vue3 文章列表组件
<!-- ArticleList.vue -->
<template>
  <div class="articles-container">
    <h2>文章列表(近7天)</h2>
    
    <!-- 加载中状态 -->
    <div class="alert alert-info" v-if="loading">加载中...</div>
    
    <!-- 错误状态 -->
    <div class="alert alert-danger" v-else-if="error">{{ error }}</div>
    
    <!-- 数据渲染 -->
    <div v-else>
      <p class="text-muted">共 {{ articles.length }} 篇文章</p>
      <div class="card" v-for="article in articles" :key="article.id">
        <div class="card-body">
          <h5 class="card-title">{{ article.title }}</h5>
          <p class="card-text">{{ article.content }}</p>
          <p class="card-subtitle text-muted">{{ article.pub_date }}</p>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import axios from 'axios';

// 响应式数据
const articles = ref([]);  // 文章列表
const loading = ref(false);  // 加载状态
const error = ref('');  // 错误信息

// 加载文章列表的函数
const fetchArticles = async () => {
  loading.value = true;  // 开始加载
  error.value = '';      // 清空错误
  
  try {
    // 调用Django接口
    const response = await axios.get('/api/articles/');
    // 适配数据格式(原生Django响应 vs DRF响应)
    articles.value = response.data.data || response.data.results;
  } catch (err) {
    error.value = '获取文章失败:' + (err.response?.data?.message || '网络错误');
    console.error('错误详情:', err);
  } finally {
    loading.value = false;  // 结束加载
  }
};

// 组件挂载时加载数据
onMounted(() => {
  fetchArticles();
});
</script>

<style scoped>
.articles-container { max-width: 1000px; margin: 20px auto; padding: 0 20px; }
.card { margin-bottom: 15px; }
</style>

四、总结

本文从 Django5 表单基础出发,逐步深入到与 Vue3 的表单交互、数据库操作,最终通过 “产品管理系统” 案例实现了完整的前后端协同流程。核心要点总结如下:

  1. Django 表单Form处理无模型关联场景,ModelForm绑定模型简化存储;
  2. 数据交互:Vue3 用axios发送 JSON / 表单数据,Django 用request.body或 DRF 接收;
  3. 数据库:配置 MySQL 后,通过 Django ORM 或 DRF 自动处理数据存储与查询;
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐