1、项目初始化
1.1 项目创建
1.2 APP的创建
1.2.1 方法一 命令配置
python manage.py startapp app01
1.2.2 方法二 Pycharm配置
在Django Structure 中创建APP
2.设计表结构
2.1 表结构
注意:
1.员工表与部门表关联时
id关联 节省存储,但是查找耗时
名称关联 加速查找
2.部门id的约束——用户表中的部门id只能是部门表中有的id
3.部门被删除,关联对应的员工表
直接删除对应员工 级联删除
对应部门的员工 部门id置空
''' 部门(与部门表连接)'''
# 1.无约束
# depart_id = models.BigIntegerField(verbose_name='部门ID')
# 2.有约束
# to:与哪张表有关
# to_field: 表中哪一列关联
# 会自动生成 depart_id列
# depart = models.ForeignKey(to="Department",to_field="id")
# 2.1部门删除
# 2.1.1 级联删除
# depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
# 2.1.2 置空删除
# depart = models.ForeignKey(to="Department",to_field="id",null=True,blank=True,on_delete=models.SET_NULL)
2.2 部门表结构
class Department(models.Model):
""" 部门表 """
title = models.CharField(max_length=32, verbose_name='部门')
2.3 员工表结构
class UserInfo(models.Model):
""" 员工表 """
name = models.CharField(max_length=16, verbose_name='姓名')
password = models.CharField(max_length=64, verbose_name='密码')
age = models.IntegerField(verbose_name='年龄')
# 金额采用decimal格式,位数10位,小数点后有两位
account = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='账户余额')
# 入职时间采用datetime格式
creat_time = models.DateTimeField(auto_now_add=True, verbose_name='入职时间')
''' 部门(与部门表连接)'''
depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
# 性别选择
gender_choice = (
(1,"男"),
(2,"女"),
)
gender = models.SmallIntegerField(verbose_name='性别',choices=gender_choice)
2.3生成数据库
2.3.1配置mysql
安装msql包
pip install mysqlclient
setting.py中
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db',
'USER': 'root',
'PASSWORD': 'root',
'HOST': 'localhost',
'PORT': 3306,
}
}
2.3.2 创建表
makemigrations [appname]
migrate [appname]
如果是数据表都已经存在了,在migrate时直接使用 --fake-initial 来处理
python manage.py migrate --fake-initial
3.案例实现
3.1 基本结构
3.2 实现逻辑
3.3 部门管理
3.3.1 部门列表的实现
depart_list.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}">
<style>
.navbar {
border-radius: 0;
}
</style>
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">用户管理系统</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="/depart/list">部门管理</a></li>
<li><a href="#">员工管理</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">登录</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">admin<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">个人中心</a></li>
<li><a href="#">设置</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">注销</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
<div style="margin-bottom: 10px">
<a type="button" class="btn btn-success" href="/depart/add"><span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span> 新建部门</a>
</div>
<div class="panel panel-default">
<div class="panel-heading">部门列表</div>
<div class="bs-example" data-example-id="hoverable-table">
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>部门名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for dept in depart_list %}
<tr>
<th scope="row">{{ dept.id }}</th>
<td>{{ dept.title }}</td>
<td>
<a class="btn btn-warning btn-sm" href="/depart/{{ dept.id }}/update">编辑</a>
<a class="btn btn-danger btn-sm" href="/depart/del?nid={{ dept.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
<script src="{% static 'js/jquery-3.7.1.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
</html>
3.3.2 部门管理的实现逻辑
- 显示部门数据
-- 获取数据信息,以depart_list传入前端
def depart_list(request):
""" 部门列表 """
'''获取数据部门信息'''
depart_list = models.Department.objects.all()
return render(request, "depart_list.html", {"depart_list": depart_list})
**************************************************************************************
-- 前端展示数据
{% for dept in depart_list %}
<tr>
<th scope="row">{{ dept.id }}</th>
<td>{{ dept.title }}</td>
<td>
<a class="btn btn-warning btn-sm" href="/depart/{{ dept.id }}/update">编辑</a>
<a class="btn btn-danger btn-sm" href="/depart/del?nid={{ dept.id }}">删除</a>
</td>
</tr>
{% endfor %}
- 增加部门数据
-- 新建按钮跳转,新建页面
<div style="margin-bottom: 10px">
<a type="button" class="btn btn-success" href="/depart/add"><span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span> 新建部门</a>
</div>
**************************************************************************************
-- 前端页面获取添加信息,返还post请求
<div class="panel panel-default">
<div class="panel-heading">部门添加</div>
<div class="panel-body">
<div class="bs-example" data-example-id="simple-form-inline">
<form class="form-inline" method="post" action="/depart/add">
{% csrf_token %}
<div class="form-group">
<label for="username">部门名称</label>
<input type="text" class="form-control" id="dept_title" name="title" placeholder="部门名称">
</div>
<input type="submit" class="btn btn-success" value="提交">
</form>
</div>
</div>
</div>
**************************************************************************************
-- 判断请求(get渲染新建页面;post接收数据,操作数据库)
-- 获取前端增添的信息,更新到数据库
def depart_add(request):
""" 部门添加 """
if request.method == 'GET':
return render(request, "depart_add.html")
title = request.POST.get("title")
models.Department.objects.create(title=title)
return redirect('/depart/list')
- 删除部门数据
-- 前端通过删除按钮获取待删除的部门id
<a class="btn btn-danger btn-sm" href="/depart/del?nid={{ dept.id }}">删除</a>
**************************************************************************************
-- del函数post请求,接收待删除的部门id,操作数据库,重定向到部门列表页面
def depart_del(request):
"""部门删除"""
# http://localhost:8000/depart/del?nid=id
nid = request.GET.get("nid")
models.Department.objects.filter(id=nid).delete()
return redirect('/depart/list')
- 修改部门数据
-- 前端通过编辑按钮获取待修改的部门id,并发送get请求,渲染修改页面
<a class="btn btn-warning btn-sm" href="/depart/{{ dept.id }}/update">编辑</a>
def depart_update(request, nid):
# http://localhost:8000/depart/nid/update
'''部门编辑'''
if request.method == 'GET':
dept = models.Department.objects.filter(id=nid).get()
return render(request, "depart_update.html", {"dept": dept})
<div class="panel-body">
<div class="bs-example" data-example-id="simple-form-inline">
<form class="form-inline" method="post" action="/depart/{{ dept.id }}/update">
{% csrf_token %}
<div class="form-group">
<label for="username">部门名称</label>
<input type="text" class="form-control" id="dept_title" name="title" value="{{ dept.title }}">
</div>
<input type="submit" class="btn btn-success" value="提交">
</form>
</div>
</div>
**************************************************************************************
-- 修改数据后,发送post请求,update函数接收请求,修改数据库
def depart_update(request, nid):
# http://localhost:8000/depart/nid/update
'''部门编辑'''
if request.method == 'GET':
dept = models.Department.objects.filter(id=nid).get()
return render(request, "depart_update.html", {"dept": dept})
new_title = request.POST.get("title")
models.Department.objects.filter(id=nid).update(title=new_title)
return redirect('/depart/list')
3.3.4 url传参的两种形式
1.get请求方法
# http://localhost:8000/depart/del?nid=id
- urls:path('depart/del', views.depart_del),
- 获取参数:<a href="/depart/del?nid={{ dept.id }}">删除</a>
- 函数:
def depart_del(request):
nid = request.GET.get("nid")
models.Department.objects.filter(id=nid).delete()
return redirect('/depart/list')t
2.正则表达式
# http://localhost:8000/depart/nid/update
- urls:path('depart/ <int:nid> /update', views.depart_update),
- 获取参数:<a href="/depart/{{ dept.id }}/update">编辑</a>
- 函数:
def depart_update(request, nid):
if request.method == 'GET':
dept = models.Department.objects.filter(id=nid).get()
return render(request, "depart_update.html", {"dept": dept})
new_title = request.POST.get("title")
models.Department.objects.filter(id=nid).update(title=new_title)
return redirect('/depart/list')
3.4模板的继承
上述部门列表、部门新建、部门更新的html页面中导航栏和一些其他的部分高度相似,为避免重复,可采用模板继承
3.4.1 模板
定义母版:layout.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugin...min.css' %}">
{% block css %}子版css内容{% endblock %}
</head>
<body>
<h1>标题</h1>
<div>
{% block content %}子版内容{% endblock %}
</div>
<h1>底部</h1>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
{% block js %}子版js内容{% endblock %}
</body>
</html>
3.4.2 继承模板
-- 继承母版
{% extends 'layout.html' %}
--自己的css内容
{% block css %}
<link rel="stylesheet" href="{% static 'pluxxx.css' %}">
<style>
...
</style>
{% endblock %}
--自己的内容
{% block content %}
<h1>首页</h1>
{% endblock %}
--自己的js内容
{% block js %}
<script src="{% static 'js/jqxxxin.js' %}"></script>
{% endblock %}
3.4.3部门案例的模板应用
定义母版:layout.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1/css/bootstrap.css' %}">
<style>
.navbar {
border-radius: 0;
}
</style>
{% block css %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-default">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">用户管理系统</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="/depart/list">部门管理</a></li>
<li><a href="#">员工管理</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">登录</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">admin<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">个人中心</a></li>
<li><a href="#">设置</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">注销</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<div class="container">
{% block content %}{% endblock %}
</div>
<script src="{% static 'js/jquery-3.7.1.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
{% block js %}{% endblock %}
</body>
</html>
dept_list.html
{% extends 'layout.html' %}
{% block content %}
<div style="margin-bottom: 10px">
<a type="button" class="btn btn-success" href="/depart/add"><span class="glyphicon glyphicon-plus-sign"
aria-hidden="true"></span> 新建部门</a>
</div>
<div class="panel panel-default">
<div class="panel-heading">部门列表</div>
<div class="bs-example" data-example-id="hoverable-table">
<table class="table table-hover">
<thead>
<tr>
<th>ID</th>
<th>部门名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for dept in depart_list %}
<tr>
<th scope="row">{{ dept.id }}</th>
<td>{{ dept.title }}</td>
<td>
<a class="btn btn-warning btn-sm" href="/depart/{{ dept.id }}/update">编辑</a>
<a class="btn btn-danger btn-sm" href="/depart/del?nid={{ dept.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
dept_add.html
{% extends 'layout.html' %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">部门添加</div>
<div class="panel-body">
<div class="bs-example" data-example-id="simple-form-inline">
<form class="form-inline" method="post" action="/depart/add">
{% csrf_token %}
<div class="form-group">
<label for="username">部门名称</label>
<input type="text" class="form-control" id="dept_title" name="title" placeholder="部门名称">
</div>
<input type="submit" class="btn btn-success" value="提交">
</form>
</div>
</div>
</div>
{% endblock %}
dept_update.html
{% extends 'layout.html' %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">部门修改</div>
<div class="panel-body">
<div class="bs-example" data-example-id="simple-form-inline">
<form class="form-inline" method="post" action="/depart/{{ dept.id }}/update">
{% csrf_token %}
<div class="form-group">
<label for="username">部门名称</label>
<input type="text" class="form-control" id="dept_title" name="title" value="{{ dept.title }}">
</div>
<input type="submit" class="btn btn-success" value="提交">
</form>
</div>
</div>
</div>
{% endblock %}
3.5员工管理
3.5.1员工列表的实现
user_list.html
{% extends 'layout.html' %}
{% block content %}
<div style="margin-bottom: 10px">
<a type="button" class="btn btn-success" href="/user/add"><span class="glyphicon glyphicon-plus-sign"
aria-hidden="true"></span> 增加员工</a>
<a
type="button" class="btn btn-success" href="/user/ModelForm/add"><span class="glyphicon glyphicon-plus-sign"
aria-hidden="true"></span> 增加员工ModelForm</a>
</div>
<div class="panel panel-default">
<div class="panel-heading">员工列表</div>
<div class="bs-example" data-example-id="hoverable-table">
<table class="table table-hover">
<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 user in user_list %}
<tr>
<th scope="row">{{ user.id }}</th>
<td>{{ user.name }}</td>
<td>{{ user.password }}</td>
<td>{{ user.age }}</td>
<td>{{ user.account }}</td>
{# <td>{% now 'Y-m-d' %}</td>#}
<td>{{ user.creat_time|date:"Y-m-d H:i:s" }}</td>
<td>{{ user.get_gender_display }}</td>
<td>{{ user.depart.title }}</td>
<td>
<a class="btn btn-warning btn-sm" href="/user/{{ user.id }}/update">编辑</a>
<a class="btn btn-danger btn-sm" href="/user/del?nid={{ user.id }}">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
views.py
def user_list(request):
'''获取用户信息'''
user_list = models.UserInfo.objects.all()
return render(request, "user_list.html", {"user_list": user_list})
<tbody> {% for user in user_list %} <tr> <th scope="row">{{ user.id }}</th> <td>{{ user.name }}</td> <td>{{ user.password }}</td> <td>{{ user.age }}</td> <td>{{ user.account }}</td> {#<td>{% now 'Y-m-d' %}</td>#} <td>{{ user.creat_time|date:"Y-m-d H:i:s" }}</td> <td>{{ user.get_gender_display }}</td> <td>{{ user.depart.title }}</td> </tr> {% endfor %} </tbody>
后端查询的用户列表返回user_list 为queryset类型
<QuerySet [<UserInfo: UserInfo object (1)>, <UserInfo: UserInfo object (7)>, <UserInfo: UserInfo object (8)>, <UserInfo: UserInfo object (9)>, <UserInfo: UserInfo object (10)>, <UserInfo: UserInfo object (11)>, <UserInfo: UserInfo object (12)>]>
1.当前时间的格式化输出
- 获取当前时间:
- python语言:
datetime.datetime.now()
- django模板语言:
{% now 'Y-m-d' %}
- 时间格式化输出
- python语言:
datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- django模板语言:
{{ {% now 'Y-m-d' %} | date:"Y-m-d" }}
2.性别的格式化输出
gender字段的定义:
gender_choice = ( (1, "男"), (2, "女"), ) gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choice)
user.gender:1或2``````user.get_gender_display:男或女
对于设置了choice的字段,Django会自动帮我们提供一个方法(注意是方法), 用来获取这个字段对应的要展示的值。展示带有choice属性的字段时,django会自动帮我们调用get_xxx_display(xxx为字段名,如本文的get_gender_display)方法,所以不用配置。而在我们自己写的模板中,这需要自己来写。并且为了简化模板的使用,默认只支持无参数的方法调用,你只需要写方法名称即可,后面的括号不能写,Django会自行帮你调用(如果是方法的话)。
3.关联数据的调用
depart字段的定义:
depart = models.ForeignKey(verbose_name='部门', to="Department", to_field="id", on_delete=models.CASCADE)
表示user中会自动生成一个depart_id的字段,来关联存储depart表的内容
因此user可以直接调用depart表的字段。user.depart.xxx(depart各字段)
3.5.2 员工的删除操作
user_list.html
<td>
<a class="btn btn-danger btn-sm" href="/user/del?nid={{ user.id }}">删除</a>
</td>
采用get方式传入,待删除数据的id数据
http://localhost:8000/user/del?nid=id
views.py
def user_del(request):
""" 员工删除"""
nid = request.GET.get("nid") # get获取(从url中)待删除数据的id
models.UserInfo.objects.filter(id=nid).delete()
return redirect("/user/list")
3.5.3 员工的增加操作
3.5.3.1 原始操作
类似员工的更新操作
user_list.html
<div style="margin-bottom: 10px">
<a type="button" class="btn btn-success" href="/user/add"><span class="glyphicon glyphicon-plus-sign"
aria-hidden="true"></span> 增加员工</a>
</div>
user_add.html
{% extends 'layout.html' %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">员工添加</div>
<div class="panel-body">
<div class="bs-example" data-example-id="simple-form-inline">
<form class="form" method="post" action="/user/add">
{% csrf_token %}
<div class="form-group">
<label>姓名</label>
<input type="text" class="form-control" id="dept_title" name="name">
</div>
<div class="form-group">
<label>密码</label>
<input type="text" class="form-control" id="dept_title" name="pwd">
</div>
<div class="form-group">
<label>年龄</label>
<input type="text" class="form-control" id="dept_title" name="age">
</div>
<div class="form-group">
<label>余额</label>
<input type="text" class="form-control" id="dept_title" name="account">
</div>
<div class="form-group">
<label>入职时间</label>
<input type="text" class="form-control" id="dept_title" name="creat_time" value="{% now 'Y-m-d' %}">
</div>
<div class="form-group">
<label>性别</label>
<select class="form-control" name="gender">
{% for item in gender_list %}
<option value="{{ item.0 }}">{{ item.1 }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>部门</label>
<select class="form-control" name="depart">
{% for item in depart_list %}
<option value="{{ item.id }}">{{ item.title }}</option>
{% endfor %}
</select>
</div>
<input type="submit" class="btn btn-success" value="提交">
</form>
</div>
</div>
</div>
{% endblock %}
同更新操作
views.py
def user_add(request):
'''新增员工'''
if request.method == 'GET':
context = {
"depart_list": models.Department.objects.all(),
"gender_list": models.UserInfo.gender_choice,
}
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("account")
creat_time = request.POST.get("creat_time")
gender = request.POST.get("gender")
depart_id = request.POST.get("depart")
models.UserInfo.objects.create(name=name, password=password, age=age, account=account, creat_time=creat_time,gender=gender, depart_id=depart_id)
return redirect('/user/list')
原始方法的弊端
- 缺少数据校验和错误提示
- 前端的每一个字段都得写一遍
- 关联的数据(depart)需要手动获取并且循环展示
3.5.3.2 form组件
views.py
class MyForm(Form):<-----------------------------------------
user = forms.CharField(widget=forms.Input) |
pwd = form.CharFiled(widget=forms.Input) |
email = form.CharFiled(widget=forms.Input) |
account = form.CharFiled(widget=forms.Input) |
create_time = form.CharFiled(widget=forms.Input) |
depart = form.CharFiled(widget=forms.Input) |
gender = form.CharFiled(widget=forms.Input) |
|
## 封装form, form = MyForm()运行自动生成input输入框 |
|
def user_add(request): |
if request.method == "GET": |
form = MyForm()>-------------------------------------
## form 此时为一系列输入框
return render(request, 'user_add.html',{"form":form})
user_add.html
<form method="post">
{% for field in form%}
{{ field }}
{% endfor %}
<!-- <input type="text" placeholder="姓名" name="user" /> -->
</form>
<form method="post">
{{ form.user }}
{{ form.pwd }}
{{ form.email }}
<!-- <input type="text" placeholder="姓名" name="user" /> -->
</form>
3.5.3.3 ModelsForm组件
views.py
class user_ModelForm(forms.ModelForm):
password = forms.CharField(min_length=6, label="密码")
class Meta:
# 自动获取UserInfo创建的各字段
model = models.UserInfo
# fields存储UserInfo创建的各字段的input输入框
fields = ['name', 'password', 'age', 'account', 'creat_time', 'gender', 'depart']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加了class="form-control"
print(self.fields) #####---------------1
for key, value in self.fields.items():
print(value.widget)
if key == "creat_time":
# python中当前时间并且格式化形式datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# django模板语言当前时间并且格式形式 {% now 'Y-m-d' %} 或 {{ user.creat_time|date:"Y-m-d" }}
value.widget.attrs = {"class": "form-control", "placeholder": value.label,
"value": datetime.datetime.now().strftime("%Y-%m-%d")}
else:
value.widget.attrs = {"class": "form-control", "placeholder": value.label}
def user_ModelForm_add(request):
if request.method == 'GET':
# form为userinfo各字段的表单
form = user_ModelForm()
print(form)
return render(request, "user_ModelForm_add.html", {"form": form})
# 将前端表单的post请求,直接传入form对象中
form = user_ModelForm(request.POST)
# 判断数据是否合法有效(校验规则————models中建表表项规则 + class user_ModelForm(forms.ModelForm)重新定义表项规则)
if form.is_valid():
# 将表单保存到数据库中
form.save()
return redirect('/user/list')
# 校验失败(在页面显示错误信息) form.error()含有错误
return render(request, "user_ModelForm_add.html", {"form": form})
输入框加入样式的方法
- widgets方法
class user_ModelForm(forms.ModelForm): password = forms.CharField(min_length=6, label="密码") class Meta: # 自动获取UserInfo创建的各字段 model = models.UserInfo # fields存储UserInfo创建的各字段的input输入框 fields = ['name', 'password', 'age', 'account', 'creat_time', 'gender', 'depart'] # 给输入框上样式的方法 widgets = { "name": forms.TextInput(attrs={"class": 'form-control'}), "password": forms.TextInput(attrs={"class": 'form-control'}), "age": forms.NumberInput(attrs={"class": 'form-control'}), "account": forms.NumberInput(attrs={"class": 'form-control'}), "creat_time": forms.DateTimeInput(attrs={"class": 'form-control'}), "gender": forms.Select(attrs={"class": 'form-control'}), "depart": forms.Select(attrs={"class": 'form-control'}), }
- 自定义方法
class user_ModelForm(forms.ModelForm): password = forms.CharField(min_length=6, label="密码") class Meta: # 自动获取UserInfo创建的各字段 model = models.UserInfo # fields存储UserInfo创建的各字段的input输入框 fields = ['name', 'password', 'age', 'account', 'creat_time', 'gender', 'depart'] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 循环找到所有的插件,添加了class="form-control" ① print(self.fields) for key, value in self.fields.items(): ② print(value.widget) if key == "creat_time": value.widget.attrs = {"class": "form-control", "placeholder": value.label, "value": datetime.datetime.now().strftime("%Y-%m-%d")} else: value.widget.attrs = {"class": "form-control", "placeholder": value.label}
要点1
# 自动获取UserInfo创建的各字段 model = models.UserInfo # fields存储UserInfo创建的各字段的input输入框 fields = ['name', 'password', 'age', 'account', 'creat_time', 'gender', 'depart']
要点2
①处field返回值为字典,key为表的各字段. value为form对象,存储form中每一个输入框格式
{ 'name': <django.forms.fields.CharField object at 0x000001CFBED9A1D0>, 'password': <django.forms.fields.CharField object at 0x000001CFBED9A410>, 'age': <django.forms.fields.IntegerField object at 0x000001CFBED9A5D0>, 'account': <django.forms.fields.DecimalField object at 0x000001CFBED9A850>, 'creat_time': <django.forms.fields.DateTimeField object at 0x000001CFBED9AAD0>, 'gender': <django.forms.fields.TypedChoiceField object at 0x000001CFBED9AD50>, 'depart': <django.forms.models.ModelChoiceField object at 0x000001CFBED9B250> }
②处self.fields.items()遍历字典的每一个键值对
key为表的各字段;value为forms对象,存储form为各字段的格式;value.widget 操作每一项的输入框
字段name为例 value: <django.forms.fields.CharField object at 0x000001CFBED9A1D0> value.widget:<django.forms.widgets.TextInput object at 0x000001DDA8476C50>
value.widget.attrs给输入框增加样式
value.widget.attrs = {"class": "form-control", "placeholder": value.label,xxx:xxx}
特别注意:使用此方法,只要使用class Department,立马输出对应内容
**此处关联数据无需遍历,只需在构建关联表时,定义默认输出值即可
class Department(models.Model): """ 部门表 """ title = models.CharField(max_length=32, verbose_name='部门') # 默认返回部门名称 def __str__(self): return self.title
若不采用,默认返回的时department的表对象,若要取得title字段,还得特殊处理
操作函数
def user_ModelForm_add(request):
if request.method == 'GET':
# form为userinfo各字段的表单
form = user_ModelForm()
① print(form)
return render(request, "user_ModelForm_add.html", {"form": form})
② # 将前端表单的post请求,直接传入form对象中
form = user_ModelForm(request.POST)
# 判断数据是否合法有效(校验规则————models中建表表项规则 + class user_ModelForm(forms.ModelForm)重新定义表项规则)
if form.is_valid():
# 将表单保存到数据库中
form.save()
return redirect('/user/list')
# 校验失败(在页面显示错误信息) form.error()含有错误
return render(request, "user_ModelForm_add.html", {"form": form})
要点1
form = user_ModelForm()
返回一个生成好的表<div> <label for="id_name">姓名:</label> <input type="text" name="name" class="form-control" placeholder="姓名" required id="id_name"> </div> <div> <label for="id_password">密码:</label> <input type="text" name="password" class="form-control" placeholder="密码" required id="id_password"> </div> <div> <label for="id_age">年龄:</label> <input type="number" name="age" class="form-control" placeholder="年龄" required id="id_age"> </div> <div> <label for="id_account">账户余额:</label> <input type="number" name="account" class="form-control" placeholder="账户余额" required id="id_account"> </div> <div> <label for="id_creat_time">入职时间:</label> <input type="text" name="creat_time" class="form-control" placeholder="入职时间" value="2024-02-21" required id="id_creat_time"> </div> <div> <label for="id_gender">性别:</label> <select name="gender" class="form-control" placeholder="性别" required id="id_gender"> <option value="" selected>---------</option> <option value="1">男</option> <option value="2">女</option> </select> </div> <div> <label for="id_depart">部门:</label> <select name="depart" class="form-control" placeholder="部门" required id="id_depart"> <option value="" selected>---------</option> <option value="1">销售部</option> <option value="2">it宣传部</option> <option value="3">计算机科学部</option> </select> </div>
要点2
前端的应用
{% extends 'layout.html' %} {% block content %} <div class="panel panel-default"> <div class="panel-heading">员工添加</div> <div class="panel-body"> <div class="bs-example" data-example-id="simple-form-inline"> <form class="form" method="post" action="/user/ModelForm/add" novalidate> {% csrf_token %} {#创建表单,form为userinfo各字段的表单#} {#每一个field都是一个字段的输入框#} {% for field in form %} <div class="form-group"> <label>{{ field.label }}</label> {{ field }} </div> {% endfor %} <input type="submit" class="btn btn-success" value="提交"> </form> </div> </div> </div> {% endblock %}
要点3:校验和错误提示
# 将前端表单的post请求,直接传入form对象中,此时的form中含有form结构以及输入的数据 form = user_ModelForm(request.POST) if form.is_valid(): # 将表单保存到数据库中 form.save() return redirect('/user/list') # 校验失败(在页面显示错误信息) form.error()含有错误 return render(request, "user_ModelForm_add.html", {"form": form})
判断数据是否合法有效
1.校验规则————models中建表表项规则class UserInfo(models.Model): """ 员工表 """ name = models.CharField(max_length=16, verbose_name='姓名') password = models.CharField(max_length=64, verbose_name='密码') age = models.IntegerField(verbose_name='年龄') # 金额采用decimal格式,位数10位,小数点后有两位 account = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='账户余额') # 入职时间采用datetime格式 creat_time = models.DateTimeField(verbose_name='入职时间') depart = models.ForeignKey(verbose_name='部门', to="Department", to_field="id", on_delete=models.CASCADE) # 性别选择 gender_choice = ( (1, "男"), (2, "女"), ) gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choice)
2.class user_ModelForm(forms.ModelForm)重新定义表项规则
> >
保存到数据库
form.save()
直接将表单字段以及对应的数据,存入数据库的对应字段
- 错误提示
此时的form中不仅存放着form结构以及输入的数据还有一系列form有效信息、错误提示等form对象含有的信息
form.error存放错误信息
field.errors.0存放错误提示的第一条信息
{% for field in form %} <div class="form-group"> <label>{{ field.label }}</label> {{ field }} <span style="color: red">{{ field.errors.0 }}</span> </div> {% endfor %}
name = models.CharField(max_length=16, verbose_name='姓名') password = models.CharField(max_length=64, verbose_name='密码') age = models.IntegerField(verbose_name='年龄') # 金额采用decimal格式,位数10位,小数点后有两位 account = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='账户余额') # 入职时间采用datetime格式 creat_time = models.DateTimeField(verbose_name='入职时间') depart = models.ForeignKey(verbose_name='部门', to="Department", to_field="id", on_delete=models.CASCADE) # 性别选择 gender_choice = ( (1, "男"), (2, "女"), ) gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choice)
2.class user_ModelForm(forms.ModelForm)重新定义表项规则
- 保存到数据库
form.save()
直接将表单字段以及对应的数据,存入数据库的对应字段
- 错误提示
此时的form中不仅存放着form结构以及输入的数据还有一系列form有效信息、错误提示等form对象含有的信息
form.error存放错误信息
field.errors.0存放错误提示的第一条信息
{% for field in form %} <div class="form-group"> <label>{{ field.label }}</label> {{ field }} <span style="color: red">{{ field.errors.0 }}</span> </div> {% endfor %}
3.5.4 员工的更新操作
3.5.4.1 原始操作
user_list.html
<td>
<a class="btn btn-warning btn-sm" href="/user/{{ user.id }}/update">编辑</a>
</td>
urls.py
path('user/<int:nid>/update', views.user_update)
可使用此种url进行传输待更新数据的id,与删除进行对比
http://localhost:8000/user/nid/update
user_update.html
{% extends 'layout.html' %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">部门修改</div>
<div class="panel-body">
<div class="bs-example" data-example-id="simple-form-inline">
<form class="form" method="post" action="/user/{{ user.id }}/update">
{% csrf_token %}
<div class="form-group">
<label>姓名</label>
<input type="text" class="form-control" id="dept_title" name="name" value="{{ user.name }}">
</div>
<div class="form-group">
<label>密码</label>
<input type="text" class="form-control" id="dept_title" name="pwd" value="{{ user.password }}">
</div>
<div class="form-group">
<label>年龄</label>
<input type="text" class="form-control" id="dept_title" name="age" value="{{ user.age }}">
</div>
<div class="form-group">
<label>余额</label>
<input type="text" class="form-control" id="dept_title" name="account"
value="{{ user.account }}">
</div>
<div class="form-group">
<label>入职时间</label>
<input type="text" class="form-control" id="dept_title" name="creat_time"
value="{{ user.creat_time|date:"Y-m-d" }}">
</div>
<div class="form-group">
<label>性别</label>
<select class="form-control" name="gender">
{% for item in gender_list %}
{% if item.1 == user.get_gender_display %}
<option value="{{ item.0 }}" selected>{{ item.1 }}</option>
{% else %}
<option value="{{ item.0 }}">{{ item.1 }}</option>
{% endif %}
{% endfor %}
</select>
</div>
<div class="form-group">
<label>部门</label>
<select class="form-control" name="depart">
{% for item in depart_list %}
{% if item.title == user.depart.title %}
<option value="{{ item.id }}" selected>{{ item.title }}</option>
{% else %}
<option value="{{ item.id }}">{{ item.title }}</option>
{% endif %}
{% endfor %}
</select>
</div>
<input type="submit" class="btn btn-success" value="保存">
</form>
</div>
</div>
</div>
{% endblock %}
<div class="form-group"> <label>入职时间</label> <input type="text" class="form-control" id="dept_title" name="creat_time" value="{{ user.creat_time|date:"Y-m-d" }}"> </div>
- 入职时间自动获取当前时间并格式化
<div class="form-group"> <label>性别</label> <select class="form-control" name="gender"> {% for item in gender_list %} {% if item.1 == user.get_gender_display %} <option value="{{ item.0 }}" selected>{{ item.1 }}</option> {% else %} <option value="{{ item.0 }}">{{ item.1 }}</option> {% endif %} {% endfor %} </select> </div>
- 性别下拉框遍历设置
- 默认值设置(遍历设置)
- choice属性采用get_gender_display调用
<div class="form-group"> <label>部门</label> <select class="form-control" name="depart"> {% for item in depart_list %} {% if item.title == user.depart.title %} <option value="{{ item.id }}" selected>{{ item.title }}</option> {% else %} <option value="{{ item.id }}">{{ item.title }}</option> {% endif %} {% endfor %} </select> </div>
- 同上
views.py
def user_update(request, nid):
"""员工更新"""
if request.method == "GET":
# context 为获取到的部门列表、性别列表、待更新用户id
# 传入前端便于操作
context = {
"depart_list": models.Department.objects.all(),
"gender_list": models.UserInfo.gender_choice,
"user": models.UserInfo.objects.get(id=nid),
}
return render(request, "user_update.html", context)
name = request.POST.get("name")
password = request.POST.get("pwd")
age = request.POST.get("age")
account = request.POST.get("account")
creat_time = request.POST.get("creat_time")
gender = request.POST.get("gender")
depart_id = request.POST.get("depart")
# 操作数据库
models.UserInfo.objects.filter(id=nid).update(name=name, password=password, age=age, account=account,creat_time=creat_time, gender=gender, depart_id=depart_id)
return redirect("/user/list")
3.5.3.2 ModelForm组件实现
user_list.html
<td>
<a class="btn btn-warning btn-sm" href="/user/ModelForm/{{ user.id }}/update">ModelForm编辑</a>
</td>
urls.py
path('user/ModelForm/<int:nid>/update', views.user_ModelForm_update),
views.py
class user_ModelForm(forms.ModelForm):
password = forms.CharField(min_length=6, label="密码")
class Meta:
# 自动获取UserInfo创建的各字段
model = models.UserInfo
# fields存储UserInfo创建的各字段的input输入框
fields = ['name', 'password', 'age', 'account', 'creat_time', 'gender', 'depart']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加了class="form-control"
for key, value in self.fields.items():
# print(value.widget)
# print(value)
if key == "creat_time":
value.widget.attrs = {"class": "form-control", "placeholder": value.label,
"value": datetime.datetime.now().strftime("%Y-%m-%d")}
else:
value.widget.attrs = {"class": "form-control", "placeholder": value.label}
def user_ModelForm_update(request, nid):
""" 编辑用户 """
# 根据nid取数据库获取要编辑的哪一行数据(行对象)
row_user = models.UserInfo.objects.filter(id=nid).first()
if request.method == "GET":
# form为userinfo各字段的表单
# instance=row_user并将row_user中各字段的数据赋值给form中各字段的值
form = user_ModelForm(instance=row_user)
return render(request, "user_ModelForm_update.html", {"form": form,"nid":nid})
# 将前端表单的post请求,直接传入form对象中
form = user_ModelForm(data=request.POST, instance=row_user)
# 判断数据是否合法有效(校验规则————models中建表表项规则 + class user_ModelForm(forms.ModelForm)重新定义表项规则)
if form.is_valid():
# 将表单保存到数据库中
form.save()
return redirect('/user/list')
# 校验失败(在页面显示错误信息) form.error()含有错误
return render(request, "user_ModelForm_update.html", {"form": form})
user_ModelForm_update.html
{% extends 'layout.html' %}
{% block content %}
<div class="panel panel-default">
<div class="panel-heading">员工编辑</div>
<div class="panel-body">
<div class="bs-example" data-example-id="simple-form-inline">
<form class="form" method="post" action="/user/ModelForm/{{ nid }}/update" novalidate>
{% csrf_token %}
{#创建表单,form为userinfo各字段的表单#}
{#每一个field都是一个字段的输入框#}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red">{{ field.errors.0 }}</span>
{#field.errors.0显示第一条错误即可#}
</div>
{% endfor %}
<input type="submit" class="btn btn-success" value="提交">
</form>
</div>
</div>
</div>
{% endblock %}
要点1
根据nid取数据库获取要编辑的哪一行数据(行对象)
row_user = models.UserInfo.objects.filter(id=nid).first()
页面发送get请求,则渲染页面
form为userinfo各字段的表单
instance=row_user并将row_user中各字段的数据赋值给form中各字段的值form = user_ModelForm(instance=row_user) form为 <div> <label for="id_name">姓名:</label> <input type="text" name="name" value="yqy" class="form-control" placeholder="姓名" required id="id_name"> </div> <div> <label for="id_password">密码:</label> <input type="text" name="password" value="123" class="form-control" placeholder="密码" required id="id_password"> </div> <div> <label for="id_age">年龄:</label> <input type="number" name="age" value="12" class="form-control" placeholder="年龄" required id="id_age"> </div> <div> <label for="id_account">账户余额:</label> <input type="number" name="account" value="1000.00" class="form-control" placeholder="账户余额" required id="id_account"> </div> <div> <label for="id_creat_time">入职时间:</label> <input type="text" name="creat_time" value="2024/02/19 00:00" class="form-control" placeholder="入职时间" value="2024-02-21" required id="id_creat_time"> </div> <div> <label for="id_gender">性别:</label> <select name="gender" class="form-control" placeholder="性别" required id="id_gender"> <option value="">---------</option> <option value="1" selected>男</option> <option value="2">女</option> </select> </div> <div> <label for="id_depart">部门:</label> <select name="depart" class="form-control" placeholder="部门" required id="id_depart"> <option value="">---------</option> <option value="1" selected>销售部</option> <option value="2">it宣传部</option> <option value="3">计算机科学部</option> </select> </div>
将form传入前端进行渲染 nid传入前端,便于跳转url
if request.method == "GET": form = user_ModelForm(instance=row_user) return render(request, "user_ModelForm_update.html", {"form": form,"nid":nid})
要点2
data=request.POST
接收前端的POST请求,获取填写的数据
instance=row_user
在原数据(row_user)的基础上修改,替换原数据,而不是新增form = user_ModelForm(data=request.POST, instance=row_user)
3.6 ModelForm与BootStrap的整合
以user_modelform_update为例
class user_ModelForm(forms.ModelForm):
password = forms.CharField(min_length=6, label="密码")
class Meta:
# 自动获取UserInfo创建的各字段
model = models.UserInfo
# fields存储UserInfo创建的各字段的input输入框
fields = ['name', 'password', 'age', 'account', 'creat_time', 'gender', 'depart']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加了class="form-control"
① print(self.fields)
for key, value in self.fields.items():
② print(value.widget)
if key == "creat_time":
value.widget.attrs = {"class": "form-control", "placeholder": value.label,
"value": datetime.datetime.now().strftime("%Y-%m-%d")}
else:
value.widget.attrs = {"class": "form-control", "placeholder": value.label}
- ModelForm可以帮助我们生成标签
class user_ModelForm(forms.ModelForm):
class Meta:
# 自动获取UserInfo创建的各字段
model = models.UserInfo
# fields存储UserInfo创建的各字段的input输入框
fields = ['name', 'password', 'age', 'account', 'creat_time', 'gender', 'depart']
form = user_ModelForm()
生成一个表单,每一个字段为一个普通的<input>输入框
{{form.name}} 普通的<input>输入框
{{form.password}} 普通的<input>输入框
{{form.age}} 普通的<input>输入框
.
.
.
-
为输入框增加样式
- widgets方法 见上
- 自定义初始化函数
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 循环找到所有的插件,添加了class="form-control" print(self.fields) for key, value in self.fields.items(): print(value.widget) if key == "creat_time": value.widget.attrs = {"class": "form-control", "placeholder": value.label, "value": datetime.datetime.now().strftime("%Y-%m-%d")} else: value.widget.attrs = {"class": "form-control", "placeholder": value.label}
生成表单与增加样式分开,自定义类
- 将自定义初始化函数写入
bootstrap.py
class BootStrapModelForm_user(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# 循环找到所有的插件,添加了class="form-control"
for key, value in self.fields.items():
# 加样式
if key == "creat_time":
# python中当前时间并且格式化形式datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# django模板语言当前时间并且格式形式 {% now 'Y-m-d' %} 或 {{ user.creat_time|date:"Y-m-d" }}
value.widget.attrs = {"class": "form-control", "placeholder": value.label,
"value": datetime.datetime.now().strftime("%Y-%m-%d"),
"id": "dt_creat_time"}
else:
value.widget.attrs = {"class": "form-control", "placeholder": value.label}
- 利用ModelForm时直接继承BootStrapModelForm_user类
class user_ModelForm(BootStrapModelForm_user):
password = forms.CharField(min_length=6, label="密码")
class Meta:
# 自动获取UserInfo创建的各字段
model = models.UserInfo
# fields存储UserInfo创建的各字段的input输入框
fields = ['name', 'password', 'age', 'account', 'creat_time', 'gender', 'depart']