Django5 与 Vue3 表单交互全解析:从基础到实战
在 Django 应用目录下创建forms.py# forms.py# 姓名:最大长度100字符,自定义标签name = forms.CharField(label='姓名', max_length=100)# 邮箱:自动验证邮箱格式email = forms.EmailField(label='邮箱')# 留言:使用文本域(Textarea)组件message = forms.CharField
在前后端分离开发日益普及的今天,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)
ModelForm
的save()
方法可直接将验证后的数据存储到数据库:
# 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 的表单交互、数据库操作,最终通过 “产品管理系统” 案例实现了完整的前后端协同流程。核心要点总结如下:
- Django 表单:
Form
处理无模型关联场景,ModelForm
绑定模型简化存储; - 数据交互:Vue3 用
axios
发送 JSON / 表单数据,Django 用request.body
或 DRF 接收; - 数据库:配置 MySQL 后,通过 Django ORM 或 DRF 自动处理数据存储与查询;
更多推荐
所有评论(0)