目录
4、新方法采用Django的Form和ModelForm组件
step 0:修改表的编码格式utf8(支持中文)创建时设置了,这步就省略。
alter table 表名 convert to character set utf8;
step 1:插入测试数据
语法:
insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id)values("刘东","123",23,100.68,"2022-09-01",1,3);
数据表中的数据:
部门表:
- mysql> select * from app01_department;
- +----+-----------+
- | id | title |
- +----+-----------+
- | 3 | 技术部 |
- | 4 | 人力部 |
- +----+-----------+
- 2 rows in set (0.00 sec)
员工表:
- mysql> desc app01_userinfo;
- +-------------+---------------+------+-----+---------+----------------+
- | Field | Type | Null | Key | Default | Extra |
- +-------------+---------------+------+-----+---------+----------------+
- | id | bigint(20) | NO | PRI | NULL | auto_increment |
- | name | varchar(16) | NO | | NULL | |
- | password | varchar(64) | NO | | NULL | |
- | age | int(11) | NO | | NULL | |
- | account | decimal(10,2) | NO | | NULL | |
- | create_time | datetime(6) | NO | | NULL | |
- | gender | smallint(6) | NO | | NULL | |
- | depart_id | bigint(20) | NO | MUL | NULL | |
- +-------------+---------------+------+-----+---------+----------------+
- 8 rows in set (0.01 sec)
step 3:查看数据表

- def user_list(request):
- """用户列表"""
- #获取数据库表中的所有对象
- queryset = models.UserInfo.objects.all()
- #测试获取内容
- for obj in queryset:
- print(obj.id,obj.name,obj.account,
- obj.create_time.strftime("%Y-%m-%d"),
- obj.get_gender_display(),
- obj.depart.title
- )
- return render(request,'user_list.html')
输出:

user_list.html
- {% extends 'layout.html' %}
- {% block content %}
- <div>
- <div class="container">
-
- <div style="margin-bottom: 10px">
- <a class="btn btn-success" href="#">
- <span class="glyphicon glyphicon-plus-sign" aria-hidden="true">span>
- 新建用户
- a>
- div>
-
- <div class="panel panel-default">
-
- <div class="panel-heading">
- <span class="glyphicon glyphicon-th-list" aria-hidden="true">span>
- 用户列表
- div>
-
- <table class="table table-bordered">
- <thead>
- <tr>
- <th>IDth>
- <th>姓名th>
- <th>密码th>
- <th>年龄th>
- <th>账户余额th>
- <th>入职时间th>
- <th>性别th>
- <th>所属部门th>
- <th>操作th>
- tr>
- thead>
- <tbody>
- {% for obj in queryset %}
- <tr>
- <th>{{ obj.id }}th>
- <td>{{ obj.name }}td>
- <td>{{ obj.password }}td>
- <td>{{ obj.age }}td>
- <td>{{ obj.account }}td>
-
- <td>{{ obj.create_time|date:"Y-m-d" }}td>
-
- <td>{{ obj.get_gender_display }}td>
- <td>{{ obj.depart.title }}td>
- <td>
- <a class="btn btn-primary btn-xs" href="#">编辑a>
- <a class="btn btn-danger btn-xs" href="#">删除a>
- td>
- tr>
- {% endfor %}
- tbody>
- table>
- div>
- div>
- div>
- {% endblock %}
-
views.py
- def user_list(request):
- """用户列表"""
- #获取数据库表中的所有对象
- queryset = models.UserInfo.objects.all()
- """
- #测试获取内容--python语法
- for obj in queryset:
- print
- (
- obj.id,obj.name,obj.account,
- obj.create_time.strftime("%Y-%m-%d"),
- obj.get_gender_display(),
- obj.depart.title
- )
- """
- return render(request,'user_list.html',{"queryset":queryset})
urls.py
- from django.contrib import admin
- from django.urls import path
- from app01 import views
-
- urlpatterns = [
- #---------------------------部门管理---------------------------
- #部门列表
- path('depart/list/', views.depart_list),
- #部门添加
- path('depart/add/', views.depart_add),
- #部门删除
- path('depart/delete/', views.depart_delete),
- #部门修改
- path('depart/
/edit/' , views.depart_edit), - #---------------------------用户管理---------------------------
- #用户列表
- path('user/list/', views.user_list),
-
- ]
访问页面:

urls.py
- #用户添加
- path('user/add/', views.user_add),
views.py
- def user_add(request):
- """用户添加"""
- #1、处理请求
- if request.method == "GET":
- return render(request,'user_add.html')
- #处理POST请求,获取表单
- name = request.POST.get("name")
- password = request.POST.get("pwd")
- age = request.POST.get("age")
- account = request.POST.get("acc")
- create_time = request.POST.get("time")
- gender = request.POST.get("gen")
- depart_id = request.POST.get("depid")
- #存到数据库
- models.UserInfo.objects.create(name=name,password=password,age=age,
- account=account,create_time=create_time,
- gender=gender,depart_id=depart_id)
- #重定向回到部门列表
- return redirect("/user/list/")
user_add.html
- {% extends 'layout.html' %}
- {% block content %}
- <div>
- <div class="container">
- <div class="panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title"> 新建用户 h3>
- div>
- <div class="panel-body">
-
- <form method="post">
- {% csrf_token %}
- <div class="form-group">
- <label> 姓名 label>
- <input type="text" class="form-control" placeholder="姓名" name="name"/>
- <label> 密码 label>
- <input type="text" class="form-control" placeholder="密码" name="pwd"/>
- <label> 年龄 label>
- <input type="text" class="form-control" placeholder="年龄" name="age"/>
- <label> 余额 label>
- <input type="text" class="form-control" placeholder="余额" name="acc"/>
- <label> 创建时间 label>
- <input type="text" class="form-control" placeholder="时间" name="time"/>
- <label> 性别 label>
- <input type="number" class="form-control" placeholder="性别" name="gen"/>
- <label> 部门ID label>
- <input type="number" class="form-control" placeholder="部门ID" name="depid"/>
- div>
-
- <button type="submit" class="btn btn-primary"> 提交button>
- form>
- div>
- div>
- div>
- div>
- {% endblock %}
测试界面:

添加用户

完成

数据库显示
上面的页面中性别和部门都是手动输入的,不够人性化,这里我们加上选择下拉框进行优化。
- <label> 性别 label>
- <select class="form-control" name="gen">
- {% for item in gender_choice %}
- <option value="{{ item.0 }}">{{ item.1 }}option>
- {% endfor %}
- select>
- <label> 部门ID label>
- <select class="form-control" name="depid">
- {% for item in depart_list %}
- <option value="{{ item.id }}">{{ item.title }}option>
- {% endfor %}
- select>
数据都是从数据库获取的:
- def user_add(request):
- """用户添加"""
- if request.method == "GET":
- context = {
- 'gender_choice': models.UserInfo.gender_choices,
- 'depart_list': models.Department.objects.all(),
- }
- return render(request, 'user_add.html', context)
- #获取用户提交的请求
- name = request.POST.get("name")
- password = request.POST.get("pwd")
- age = request.POST.get("age")
- account = request.POST.get("acc")
- create_time = request.POST.get("time")
- gender = request.POST.get("gen")
- depart_id = request.POST.get("depid")
- # 存到数据库
- models.UserInfo.objects.create(name=name, password=password, age=age,
- account=account, create_time=create_time,
- gender=gender, depart_id=depart_id)
- # 重定向回到部门列表
- return redirect("/user/list/")
页面:

urls.py
- #用户删除
- path('user/delete/', views.user_delete),
views.py
- def user_delete(request):
- """删除用户"""
- uid = request.GET.get("uid")
- models.UserInfo.objects.filter(id=uid).delete()
- return redirect("/user/list/")
修改 user_list.html
将按钮绑定网址
<a class="btn btn-danger btn-xs" href="/user/delete/?uid={{ obj.id }}">删除a>
网页测试:
删除

数据库

urls.py
- #用户修改
- path('user/
/edit/' , views.user_edit),
views.py
- def user_edit(request,uid):
- #处理用户GET请求
- if request.method == "GET":
- row_object = models.UserInfo.objects.filter(id=uid).first()
- return render(request, 'user_edit.html', {"row_object": row_object})
- #处理POST请求
- name = request.POST.get("name")
- password = request.POST.get("pwd")
- age = request.POST.get("age")
- account = request.POST.get("acc")
- create_time = request.POST.get("time")
- gender = request.POST.get("gen")
- depart_id = request.POST.get("depid")
- #修改数据表
- models.UserInfo.objects.filter(id=uid).update(name=name,password=password,age=age,
- account=account,create_time=create_time,
- gender=gender,depart_id=depart_id)
- # 重定向用户列表
- return redirect("/user/list/")
修改user_list.html绑定按钮
<a class="btn btn-primary btn-xs" href="/user/{{ obj.id }}/edit/">编辑a>
user_edit.py
- {% extends 'layout.html' %}
- {% block content %}
- <div>
- <div class="container">
- <div class="panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title"> 修改用户 h3>
- div>
- <div class="panel-body">
-
- <form method="post">
- {% csrf_token %}
- <div class="form-group">
- <label> 姓名 label>
- <input type="text" class="form-control" placeholder="姓名" name="name"
- value="{{ row_object.name }}"/>
- <label> 密码 label>
- <input type="text" class="form-control" placeholder="密码" name="pwd"
- value="{{ row_object.password }}"/>
- <label> 年龄 label>
- <input type="text" class="form-control" placeholder="年龄" name="age"
- value="{{ row_object.age }}"/>
- <label> 余额 label>
- <input type="text" class="form-control" placeholder="余额" name="acc"
- value="{{ row_object.account }}"/>
- <label> 入门时间 label>
- <input type="text" class="form-control" placeholder="入门时间" name="time"
- value="{{ row_object.create_time|date:"Y-m-d" }}"/>
- <label> 性别 label>
- <input type="text" class="form-control" placeholder="性别" name="gen"
- value="{{ row_object.gender }}"/>
- <label> 部门ID label>
- <input type="text" class="form-control" placeholder="部门ID" name="depid"
- value="{{ row_object.depart_id }}"/>
- div>
-
- <button type="submit" class="btn btn-primary"> 提交button>
- form>
- div>
- div>
- div>
- div>
- {% endblock %}
测试:

修改

提交
数据库

(1)用户提交的数据没有校验,不能判断数据是否为空。

(2)如果页面信息输入错误,没有提示
(3)页面上,每一个字段都要手写一遍,代码量太大

(4)关联数据需要手动获取并循环展示在页面。


因为以上种种问题,企业开发根本不会用这种原始方法,而是会选择使用django的组件,处理这些事件。
示例:

(蓝色部分已被取代了不用写了)

更简单点使用循环:

如果觉得Form的方法还是过于啰嗦,尤其是创建类的时候,和models的写法很像

models.py

那么,为了更好的表达这种转换关系,我们使用ModelForm。

modelForm还可以自定义字段

更多实用功能,后续介绍。
创建一个新的添加页面,基于modelform
user_list.html
-
- <div style="margin-bottom: 10px">
- <a class="btn btn-success" href="/user/add/">
- <span class="glyphicon glyphicon-plus-sign" aria-hidden="true">span>
- 新建用户
- a>
- <a class="btn btn-success" href="/user/modelform/add/">
- <span class="glyphicon glyphicon-plus-sign" aria-hidden="true">span>
- 新建用户ModelForm
- a>
- div>
样式

urls.py
- #用户添加ModelForm
- path('user/modelform/add/', views.user_model_add),
views.py
- #————————————————————————————————————————————————ModelForm实例————————————————————————————————————————————————
- from django import forms
-
- class UserModelForm(forms.ModelForm):
- class Meta:
- model = models.UserInfo
- fields = ["name","password","age","account","create_time"]
- def user_model_add(request):
- """添加用户(ModelForm)"""
- #类实例化
- form = UserModelForm()
- return render(request,'user_mode_add.html',{'form':form})
user_model_add.html
- html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Titletitle>
- head>
- <body>
- <div>
- <form method="post">
- {% csrf_token %}
-
- {{ form.name.label}}:{{ form.name }}
-
- {% for foo in form %}
- {{ foo.label }}:{{ foo }}
- {% endfor %}
- form>
- div>
- body>
- html>
测试页面:

在列表中加入gender和create_time和depart也是可以的,但是depart作为关联数据库返回的是对象值:

想要在输出对象时显示对象里面的内容,可以在类中创建一个__str__(self)函数。

所以,根据这个原理,我们去models.py的部门类中填写一个函数
- class Department(models.Model):
- """部门表"""
- #id = models.BigAutoField(verbose_name='id',primary_key=True)#手动设置自增主键
- title = models.CharField(verbose_name='部门标题',max_length=32)#verbose_name是给自己看的注释,不会影响数据库
- #输出对象时的返回值
- def __str__(self):
- return self.title
显示内容:

--------------------------------------------------------------------------------------------------------------------------------
完整示例:
views.py
usermodelform类
- class UserModelForm(forms.ModelForm):
- #字段重构:编写验证规则
- name = forms.CharField(min_length=3,label="姓名")
- password = forms.CharField(min_length=6,label="密码")#validators:正则表达式,密码是6-18位数字
- # 重新定义ini方法
- def __init__(self, *args, **kwargs):
- # 引用父类的ini方法
- super().__init__(*args, **kwargs)
- for name, field in self.fields.items():
- # print(name,field)
- # if name == "password":
- # continue
- field.widget.attrs = {"class": "form-control", "placeholder": field.label}
-
- class Meta:
- model = models.UserInfo
- fields = ["name", "password", "age", "account", "create_time", "gender", "depart"]
- # 样式标签
- # widgets = {
- # 输入框标签
- # "name":forms.TextInput(attrs={'class':'form-control'}),
- # "password":forms.PasswordInput(attrs={'class':'form-control'}),
- # ……
- # }
-
user_model_add函数
- def user_model_add(request):
- """添加用户(ModelForm)"""
- if request.method == "GET":
- # 类实例化
- form = UserModelForm()
- return render(request, 'user_mode_add.html', {'form': form})
- #处理POST请求并校验数据
- form = UserModelForm(data=request.POST)
- if form.is_valid():#校验成功
- #数据合法,保存数据
- #{'name': '小样', 'password': '111', 'age': 11, 'account': Decimal('0'), 'create_time': datetime.datetime(2022, 10, 1, 0, 0, tzinfo=
), 'gender': 2, 'depart': } - #print(form.cleaned_data)
- form.save()
- return redirect("/user/list/")
- #校验失败,在页面上显示错误信息
- #print(form.errors)
- return render(request, 'user_mode_add.html', {'form': form})
models.py
- class Department(models.Model):
- """部门表"""
- #id = models.BigAutoField(verbose_name='id',primary_key=True)#手动设置自增主键
- title = models.CharField(verbose_name='部门标题',max_length=32)#verbose_name是给自己看的注释,不会影响数据库
- #输出对象时的返回值
- def __str__(self):
- return self.title
user_model_add.html
- {% extends 'layout.html' %}
- {% block content %}
- <div>
- <div class="container">
- <div class="panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title"> 新建用户 h3>
- div>
- <div class="panel-body">
-
-
- <form method="post" novalidate>
- {% csrf_token %}
- {% for obj in form %}
- <div class="form-group">
- <label> {{ obj.label }} label>
- {{ obj }}
- <span style="color:red"> {{ obj.errors.0 }}span>
-
- div>
- {% endfor %}
- <button type="submit" class="btn btn-primary"> 提交button>
- form>
- div>
- div>
- div>
- div>
- {% endblock %}
将错误提示改成中文

setting.py
- #LANGUAGE_CODE = 'en-us'
- LANGUAGE_CODE = 'zh-hans'
舒服多了

演示:


如果操作针对数据库建议使用ModelForm,否则使用Form。
流程:点击编辑,跳转到编辑页面,同时用url传递编辑行的用户id参数。
需求;编辑页面要有默认数据,并且提交时有错误提示,并将正确信息保存在数据库。
user_list.html
<a class="btn btn-primary btn-xs" href="/user/{{ obj.id }}/edit/">编辑a>
urls.py
- #用户修改ModelForm
- path('user/
/edit/' , views.user_model_edit),
views.py:
- def user_model_edit(request, nid):
- #获取当前行数据
- row_object = models.UserInfo.objects.filter(id=nid).first()
- if request.method == "GET":
- #将默认值传递给页面
- form = UserModelForm(instance=row_object)
- return render(request, 'user_model_edit.html',{"form":form})
- #处理post请求
- form = UserModelForm(data=request.POST,instance=row_object)
- # 校验
- if form.is_valid():
- form.save()
- return redirect("/user/list/")
- return render(request,'user_model_edit.html',{"form":form})
user_model_edit.html
- {% extends 'layout.html' %}
- {% block content %}
- <div>
- <div class="container">
- <div class="panel panel-default">
- <div class="panel-heading">
- <h3 class="panel-title"> 编辑用户 h3>
- div>
- <div class="panel-body">
-
-
- <form method="post" novalidate>
- {% csrf_token %}
- {% for obj in form %}
- <div class="form-group">
- <label> {{ obj.label }} label>
- {{ obj }}
- <span style="color:red"> {{ obj.errors.0 }}span>
-
- div>
- {% endfor %}
- <button type="submit" class="btn btn-primary"> 提交button>
- form>
- div>
- div>
- div>
- div>
- {% endblock %}
测试页面:


小提示1:数据表时间字段中将DatetimeFiled修改为DateFiled可以省略时分秒,

但是,只要变更数据库,就要执行迁移指令:
打开

输入
- makemigrations
- migrate
完成。
使用ModelForm额外添加字段
