目录
4、新方法采用Django的Form和ModelForm组件
0、在数据库写入测试数据
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:查看数据表
1、在后端测试获取数据表中内容
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')
输出:
2、加载用户列表
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">
<!-- Default panel contents -->
<div class="panel-heading">
<span class="glyphicon glyphicon-th-list" aria-hidden="true"></span>
用户列表
</div>
<!-- Table -->
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<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.strftime("%Y-%m-%d") }</td>-->
<td>{
{ obj.create_time|date:"Y-m-d" }}</td>
<!--模板中参数无括号,括号是自动加的<td>{ obj.get_gender_display() }</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/<int:nid>/edit/', views.depart_edit),
#---------------------------用户管理---------------------------
#用户列表
path('user/list/', views.user_list),
]
访问页面:
3、原始操作方法
(1)添加用户
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"><!--action可以不写,因为不写的话提交的是当前地址-->
{% 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/")
页面:
(2)删除用户
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>
网页测试:
删除
数据库
(3)编辑用户
urls.py
#用户修改
path('user/<int:uid>/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"><!--action可以不写,因为不写的话提交的是当前地址-->
{% 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 %}
测试:
修改
提交
数据库
4、新方法采用Django的Form和ModelForm组件
4.1 原始办法的缺点:
(1)用户提交的数据没有校验,不能判断数据是否为空。
(2)如果页面信息输入错误,没有提示
(3)页面上,每一个字段都要手写一遍,代码量太大
(4)关联数据需要手动获取并循环展示在页面。
因为以上种种问题,企业开发根本不会用这种原始方法,而是会选择使用django的组件,处理这些事件。
4.2 Form组件
示例:
(蓝色部分已被取代了不用写了)
更简单点使用循环:
4.3ModelForm组件
如果觉得Form的方法还是过于啰嗦,尤其是创建类的时候,和models的写法很像
models.py
那么,为了更好的表达这种转换关系,我们使用ModelForm。
modelForm还可以自定义字段
更多实用功能,后续介绍。
4.4 基于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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<form method="post">
{% csrf_token %}
<!--因为formmodel是models的一种转化引用,所以models里面定义的内容,在formmodel中也可以引用-->
{
{ 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=<UTC>), 'gender': 2, 'depart': <Department: 人力部>}
#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">
<!--表单-->
<!--action可以不写,因为不写的话提交的是当前地址-->
<form method="post" novalidate><!--novalidate:表示不采用views函数里的校验,采用自己写的页面校验-->
{% csrf_token %}
{% for obj in form %}
<div class="form-group">
<label> {
{ obj.label }} </label>
{
{ obj }}
<span style="color:red"> {
{ obj.errors.0 }}</span><!--错误信息以列表形式存储-->
<!--<input type="text" class="form-control" placeholder="姓名" name="name"/>-->
</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'
舒服多了
演示:
4.5 基于ModelForm组件-实现用户修改
如果操作针对数据库建议使用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/<int:nid>/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">
<!--表单-->
<!--action可以不写,因为不写的话提交的是当前地址-->
<form method="post" novalidate><!--novalidate:表示不采用views函数里的校验,采用自己写的页面校验-->
{% csrf_token %}
{% for obj in form %}
<div class="form-group">
<label> {
{ obj.label }} </label>
{
{ obj }}
<span style="color:red"> {
{ obj.errors.0 }}</span><!--错误信息以列表形式存储-->
<!--<input type="text" class="form-control" placeholder="姓名" name="name"/>-->
</div>
{% endfor %}
<button type="submit" class="btn btn-primary"> 提交</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
测试页面:
小提示1:
数据表时间字段中将DatetimeFiled修改为DateFiled可以省略时分秒,
但是,只要变更数据库,就要执行迁移指令:
打开
输入
makemigrations
migrate
完成。
小提示2:
使用ModelForm额外添加字段