表单是搜集用户数据信息的各种表单元素的合集,其作用是实现网页上的数据交互,比如用户在网站输入数据信息,然后提交到网站服务器进行处理(如数据录入和用户登陆注册),分为django.forms.Form:基础的表单功能,django.forms.ModelForm:在基础上结合模型所生成的数据表单。
1.传统表单在模板文件中编写HTML标签实现
完整的表单包括:
- 提交地址:(form标签的action属性)用于设置用户提交的表单数据应有哪个路由接收和处理。当用户向服务器提交数据时,若属性action为空,则提交的数据应当由当前的路由接受和处理,否则网页会跳转到属性action所指向的路由地址。
- 请求方式:设置表单的提交方式,通常是GET请求或POST请求,由form标签的method决定。
- 元素控件:供用户输入数据信息的输入框,由HTML的控件实现,控件属性type用于设置输入框的类型,常用的输入框有文本框、下拉框、复选框。
- 提交按钮:供用户提交数据到服务器,该按钮由HTML的控件实现。但该按钮具有一定的特殊性,因此不归纳到元素控件的范围内。
2.视图里使用Form和ModelForm
1. 在models.py中创建数据库模型
from django.db import models
# Create your models here.
class PersonInfo(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
age = models.IntegerField()
def __str__(self):
return self.name
class Meta:
verbose_name = '人员信息'
class Vocation(models.Model):
id = models.AutoField(primary_key=True)
job = models.CharField(max_length=20)
title = models.CharField(max_length=20)
payment = models.IntegerField(null=True, blank=True)
person = models.ForeignKey(PersonInfo, on_delete=models.CASCADE)
def __str__(self):
return str(self.id)
class Meta:
verbose_name = '职业信息'
2.迁移数据库
3.创建表单form.py
from django import forms
from .models import *
class PersonInfoForm(forms.ModelForm):
class Meta:
model = PersonInfo
fields = '__all__'
class VocationForm(forms.ModelForm):
class Meta:
model = Vocation
fields = '__all__'
labels = {
'job': '职位',
'title': '职称',
'payment': '薪资',
'person': '姓名'
}
error_messages = {
'__all__': {'required': '请输入内容',
'invalid': '请检查输入内容'},
}
# 自定义表单字段payment的数据清洗
def clean_payment(self):
data = self.cleaned_data['payment'] + 10
return data
4.views.py中添加交互信息
from django.shortcuts import render
from django.http import HttpResponse
from .form import *
from .models import *
def index(request):
# GET请求
if request.method == 'GET':
id = request.GET.get('id', '')
if id:
i = Vocation.objects.filter(id=id).first()
# 将参数i传入表单VocationForm执行实例化
v = VocationForm(instance=i, prefix='vv')
else:
v = VocationForm(prefix='vv')
return render(request, 'index.html', locals())
# POST请求
else:
# 由于在GET请求设置了参数prefix
# 实例化时设置参数prefix,否则无法获取POST的数据
v = VocationForm(data=request.POST, prefix='vv')
# is_valid()会使字段payment自增加10
if v.is_valid():
# 根据请求参数id查询模型数据是否存在
id = request.GET.get('id')
result = Vocation.objects.filter(id=id)
# 数据不存在,则新增数据
if not result:
# 数据保存方法一
# 直接将数据保存到数据库
# v.save()
# 数据保存方法二
# 将save的参数commit=False
# 生成数据库对象v1,修改v1的属性值并保存
v1 = v.save(commit=False)
v1.title = '初级' + v1.title
v1.save()
# 数据保存方法三
# save_m2m()方法用于保存ManyToMany的数据模型
# v.save_m2m()
return HttpResponse('新增成功')
# 数据存在,则修改数据
else:
d = v.cleaned_data
d['title'] = '中级' + d['title']
result.update(**d)
return HttpResponse('修改成功')
else:
# 获取错误信息,并以json格式输出
error_msg = v.errors.as_json()
print(error_msg)
return render(request, 'index.html', locals())
5.index.html中写显示页面
```bash
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{% if v.errors %}
<p>
数据出错啦,错误信息:{{ v.errors }}
</p>
{% else %}
<form action="" method="post">
{% csrf_token %}
<table>
{{ v.as_table }}
</table>
<input type="submit" value="提交">
</form>
{% endif %}
</body>
</html>
表单类Form和模型实现数据交互需要注意以下事项:
- 表单字段最好与模型字段相同,否则两者在进行数据交互时,必须将两者的字段进行转化。
- 使用同一个表单并且需要多次实例化表单时,除了参数initial和data的数据不同之外,其他参数设置必须相同,否则无法接受上一个表单对象所传递的数据信息。
- 参数initial是表单实例化的初始数据,它只适用于模型数据传递给表单,再由表单显示在网页上;参数data是在表单实例化之后,再将数据传递给实例化对象,只适用于表单接收HTTP请求的请求参数。
- 参数prefix设置表单的控件属性name和id的值,若在一个网页里使用同一个表单生成多个不同的网页表单,参数prefix可分区每个网页表单,则在接收或设置某个表单数据时不会与其他表单数据混淆。
模型表单ModelForm实现数据保存只有save()和save_m2m()两种方法。使用save()保存数据时,参数commit的值会影响数据的保存方式。如果参数commit为True,就直接将表单保存到数据库;如果参数commit为False,就会生成一个数据库对象,然后可以对该对象进行增、删、改、查等数据操作,再将修改后的数据保存到数据库。
save()只适合将数据保存在非多对多关系的数据表中,save_m2m()只适合将数据保存在多对多关系的数据表中。