Django—Form两种解决表单数据无法动态刷新的方法

时间:2022-09-11 13:32:52

一、无法动态更新数据的实例

1. 如下,数据库中创建了班级表和教师表,两张表的对应关系为“多对多”

Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 from django.db import models
2
3
4 class Classes(models.Model):
5 title = models.CharField(max_length=32)
6
7
8 class Teacher(models.Model):
9 name = models.CharField(max_length=32)
10 t2c = models.ManyToManyField(Classes)
models.py

2. views的功能有查看、添加、编辑班级或教师表

Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 from django.shortcuts import render, redirect
2 from school import models
3 from django.forms import Form, fields, widgets
4
5
6 #班级表单验证规则
7 class ClsForm(Form):
8 title = fields.RegexField('老男孩', error_messages={'invalid': '请以 老男孩 开头'})
9
10
11 #教师表单验证规则
12 class TchForm(Form):
13 name = fields.CharField(max_length=16, min_length=2, widget=widgets.TextInput(attrs={'class': 'form-control'}))
14 t2c = fields.MultipleChoiceField(
15 choices=models.Classes.objects.values_list('id', 'title'),
16 widget=widgets.SelectMultiple(attrs={'class': 'form-control'})
17 )
18
19
20 #查看班级列表
21 def classes(request):
22 cls_list = models.Classes.objects.all()
23 return render(request, 'classes.html', {'cls_list': cls_list})
24
25
26 #查看教师列表
27 def teachers(request):
28 tch_list = models.Teacher.objects.all()
29 return render(request, 'teachers.html', {'tch_list': tch_list})
30
31
32 #添加班级
33 def add_cls(request):
34 if request.method == 'GET':
35 obj = ClsForm()
36 return render(request, 'add_classes.html', {'obj': obj})
37 else:
38 obj = ClsForm(request.POST)
39 if obj.is_valid():
40 models.Classes.objects.create(**obj.cleaned_data)
41 return redirect('/school/classes/')
42 return render(request, 'add_classes.html', {'obj': obj})
43
44
45 #添加教师
46 def add_tch(request):
47 if request.method == 'GET':
48 obj = TchForm()
49 return render(request, 'add_teacher.html', {'obj': obj})
50 else:
51 obj = TchForm(request.POST)
52 if obj.is_valid():
53 tc = obj.cleaned_data.pop('t2c') # 获取教师任课班级id
54 tch_obj = models.Teacher.objects.create(name=obj.cleaned_data['name']) # 添加新教师姓名
55 tch_obj.t2c.add(*tc) # 添加新教师任课班级
56 return redirect('/school/teachers/')
57 return render(request, 'add_teacher.html', {'obj': obj})
58
59
60 #编辑班级
61 def edit_cls(request, nid):
62 if request.method == 'GET':
63 cls = models.Classes.objects.filter(id=nid).first()
64 obj = ClsForm(initial={'title': cls.title})
65 return render(request, 'edit_classes.html', {'nid': nid, 'obj': obj})
66 else:
67 obj = ClsForm(request.POST)
68 if obj.is_valid():
69 models.Classes.objects.filter(id=nid).update(**obj.cleaned_data)
70 return redirect('/school/classes/')
71 return render(request, 'edit_classes.html', {'nid': nid, 'obj': obj})
72
73
74 #编辑教师
75 def edit_tch(request, nid):
76 if request.method == 'GET':
77 tch = models.Teacher.objects.filter(id=nid).first()
78 v = tch.t2c.values_list('id') # 获取该教师任课班级的id
79 cls_ids = list(zip(*v))[0] if list(zip(*v)) else [] # 格式化为列表类型
80 obj = TchForm(initial={'name': tch.name, 't2c': cls_ids})
81 return render(request, 'edit_teacher.html', {'nid': nid, 'obj': obj})
82 else:
83 obj = TchForm(request.POST)
84 if obj.is_valid():
85 tc = obj.cleaned_data.pop('t2c') # 获取修改后的任课班级id
86 # models.Teacher.objects.filter(id=nid).update(name=obj.cleaned_data['name']) # 更新教师姓名方法1
87 tch_obj = models.Teacher.objects.filter(id=nid).first()
88 tch_obj.name = obj.cleaned_data['name'] # 更新教师姓名方法2
89 tch_obj.save()
90 tch_obj.t2c.set(tc)
91 return redirect('/school/teachers/')
92 return render(request, 'edit_teacher.html', {'nid': nid, 'obj': obj})
views.py

3. html文件

classe:

Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>班级列表</title>
6 <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css">
7 </head>
8 <body>
9 <div style="width: 700px; margin: 30px auto">
10 <a class="btn btn-default" href="/school/add_cls/" style="margin-bottom: 10px">添加班级</a>
11 <table class="table table-hover" border="1" cellspacing="0">
12 <thead>
13 <tr>
14 <th>ID</th>
15 <th>班级</th>
16 <th>操作</th>
17 </tr>
18 </thead>
19 <tbody>
20 {% for item in cls_list %}
21 <tr>
22 <td>{{ item.id }}</td>
23 <td>{{ item.title }}</td>
24 <td><a href="/school/edit_cls/{{ item.id }}">编辑</a></td>
25 </tr>
26 {% endfor %}
27 </tbody>
28 </table>
29 </div>
30 </body>
31 </html>
classes.html
Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>添加班级</title>
6 </head>
7 <body>
8 <h1>添加班级</h1>
9 <form action="/school/add_cls/" method="post">
10 {% csrf_token %}
11 <p>
12 {{ obj.title }} {{ obj.errors.title.0 }}
13 </p>
14 <input type="submit" value="提交">
15 </form>
16 </body>
17 </html>
add_classes.html
Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>编辑班级</title>
6 </head>
7 <body>
8 <h1>编辑班级</h1>
9 <form action="/school/edit_cls/{{ nid }}" method="post">
10 {% csrf_token %}
11 <p>
12 {{ obj.title }} {{ obj.errors.title.0 }}
13 </p>
14 <input type="submit" value="提交">
15 </form>
16 </body>
17 </html>
edit_classes.html

 teachers:

Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>教师列表</title>
6 <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css">
7 </head>
8 <body>
9 <div style="width: 700px; margin: 30px auto">
10 <a class="btn btn-default" href="/school/add_tch/" style="margin-bottom: 10px">添加教师</a>
11 <table class="table table-hover" border="1" cellspacing="0">
12 <thead>
13 <tr>
14 <th>ID</th>
15 <th>姓名</th>
16 <th>任教班级</th>
17 <th>操作</th>
18 </tr>
19 </thead>
20 <tbody>
21 {% for item in tch_list %}
22 <tr>
23 <td>{{ item.id }}</td>
24 <td>{{ item.name }}</td>
25 <td>
26 {% for row in item.t2c.all %}
27 <span style="border: solid gray 1px">{{ row.title }}</span>
28 {% endfor %}
29 </td>
30 <td><a href="/school/edit_tch/{{ item.id }}">编辑</a></td>
31 </tr>
32 {% endfor %}
33 </tbody>
34 </table>
35 </div>
36 </body>
37 </html>
teachers.html
Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>添加教师</title>
6 <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css">
7 </head>
8 <body>
9 <div style="width: 500px; margin: 20px auto">
10 <h3 style="width: 100px; margin: 10px auto">添加教师</h3>
11 <form class="form-horizontal" action="/school/add_tch/" method="post">
12 {% csrf_token %}
13 <div class="form-group">
14 <label class="col-sm-2 control-label">姓名</label>
15 <div class="col-sm-10">
16 {{ obj.name }} {{ obj.errors.name.0 }}
17 </div>
18 </div>
19 <div class="form-group">
20 <label class="col-sm-2 control-label">班级</label>
21 <div class="col-sm-10">
22 {{ obj.t2c }} {{ obj.errors.t2c.0 }}
23 </div>
24 </div>
25 <div class="form-group">
26 <div class="col-sm-offset-2 col-sm-10">
27 <input type="submit" class="btn btn-default" value="提交"></input>
28 </div>
29 </div>
30 </form>
31 </div>
32 </body>
33 </html>
add_teacher.html
Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 <!DOCTYPE html>
2 <html lang="en">
3 <head>
4 <meta charset="UTF-8">
5 <title>编辑教师</title>
6 <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css">
7 </head>
8 <body>
9 <div style="width: 500px; margin: 20px auto">
10 <h3 style="width: 100px; margin: 10px auto">编辑教师</h3>
11 <form class="form-horizontal" action="/school/edit_tch/{{ nid }}" method="post">
12 {% csrf_token %}
13 <div class="form-group">
14 <label class="col-sm-2 control-label">姓名</label>
15 <div class="col-sm-10">
16 {{ obj.name }} {{ obj.errors.name.0 }}
17 </div>
18 </div>
19
20 <div class="form-group">
21 <label class="col-sm-2 control-label">班级</label>
22 <div class="col-sm-10">
23 {{ obj.t2c }} {{ obj.errors.t2c.0 }}
24 </div>
25 </div>
26 <div class="form-group">
27 <div class="col-sm-offset-2 col-sm-10">
28 <input type="submit" class="btn btn-default" value="提交"></input>
29 </div>
30 </div>
31 </form>
32 </div>
33 </body>
34 </html>
edit_teacher.html

4. 数据不能同步

在班级表中新增一条记录

Django—Form两种解决表单数据无法动态刷新的方法

在教师表中新添加一名教师,发现无法获取上一步新增记录

Django—Form两种解决表单数据无法动态刷新的方法

5. 原因分析

在添加教师时,请求方式为GET,html标签由Form组件自动生成,其中的数据也是由Form组件提供

Django—Form两种解决表单数据无法动态刷新的方法

而TchForm作为一个类,在project运行起来后,其中的name和t2c字段都是类的变量,其只执行一次,就将数据保存在内存中,无论之后生成多少个TchForm对象,其中的字段的值都不变。

所以会出现教师表中的班级多选列表无法动态更新。

Django—Form两种解决表单数据无法动态刷新的方法

二、解决上述bug的方法

每次更新数据库后重启project,让Form类重新初始化,能够让数据更新,但这显然是不切实际的。

知道了bug的根源,我们可以尝试让每次生成TchForm对象时就更新数据:

方法一

1. 利用 __init__将数据库操作放入对象变量中

Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 #教师表单验证规则
2 class TchForm(Form):
3 name = fields.CharField(max_length=16, min_length=2, widget=widgets.TextInput(attrs={'class': 'form-control'}))
4 t2c = fields.MultipleChoiceField(
5 # choices=models.Classes.objects.values_list('id', 'title'),
6 widget=widgets.SelectMultiple(attrs={'class': 'form-control'})
7 )
8
9 def __init__(self, *args, **kwargs): # 自定义__init__
10 super(TchForm, self).__init__(*args, **kwargs) # 调用父类的__init__
11 self.fields['t2c'].choices = models.Classes.objects.values_list('id', 'title') # 为字段t2c的choices赋值
修改TchForm类

2. 验证

 在班级表中新增一条记录

Django—Form两种解决表单数据无法动态刷新的方法

 再在教师表中添加

Django—Form两种解决表单数据无法动态刷新的方法

方法二

1. 利用django.forms.models模块中的queryset连接数据库

Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
 1 #教师表单验证规则
2 from django.forms import models as form_models # 导入django.forms.models
3 class TchForm(Form):
4 name = fields.CharField(max_length=16, min_length=2, widget=widgets.TextInput(attrs={'class': 'form-control'}))
5 #重新定义字段
6 t2c = form_models.ModelMultipleChoiceField(
7 # choices=models.Classes.objects.values_list('id', 'title'),
8 queryset=models.Classes.objects.all(), # 利用queryset连接数据库,只能连接object类型
9 widget=widgets.SelectMultiple(attrs={'class': 'form-control'})
10 )
修改TchForm类

2. 验证

由于TchForm类中,queryset只能连接object类型,所以,需要设置models.py中的Classes类的返回值。

Django—Form两种解决表单数据无法动态刷新的方法Django—Form两种解决表单数据无法动态刷新的方法
1 class Classes(models.Model):
2 title = models.CharField(max_length=32)
3
4 def __str__(self):
5 return self.title
设置models.py中的Classes类的返回值

在班级表中新增一条记录

Django—Form两种解决表单数据无法动态刷新的方法

再在教师表中添加

Django—Form两种解决表单数据无法动态刷新的方法