上一篇:
Django 02 :部门管理 【面板设计(Bootstrap)+部门的增删改查(Django+MySQL)】_.末明.的博客-CSDN博客
1、模板的继承
上一篇文章中我们发现,我们每创建一个新页面(HTML文件),都要重复的去做引入静态文件、导航条等操作,下面提供一个更简单的方式:模板继承
定义母版:layout.html
母版包含内容:
如下,我们规定好母版的内容,此时子板只需要填写{% block content %}{% endblock %} 的内容就ok了
{% 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.min.css' %}">
<style>
.navbar {
border-radius: 0;
}
</style>
</head>
<body>
{# 子板部分 #}
<div>
{% block content %}{% endblock %}
</div>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
<script src="{% static 'plugins/bootstrap-3.4.1/js/bootstrap.min.js' %}"></script>
</body>
</html>
子模板:
{% extends 'layout.html' %}
{% block content %}
{# 子板的内容 #}
{% endblock %}
当然,我们还可以在模板中多添加点block,如下,我们新增了css、js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="{% static 'plugin...min.css' %}">
{% block css %}{% endblock %}
</head>
<body>
<div>
{% block content %}{% endblock %}
</div>
<script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
{% block js %}{% endblock %}
</body>
</html>
继承母版:
{% extends 'layout.html' %}
{% block css %}
<link rel="stylesheet" href="{% static 'pluxxx.css' %}">
<style>
...
</style>
{% endblock %}
{% block content %}
<h1>首页</h1>
{% endblock %}
{% block js %}
<script src="{% static 'js/jqxxxin.js' %}"></script>
{% endblock %}
这样我们就可以重构一下之前的前端代码:
2、用户管理
urls.py
path('user/list/', views.user_list),
views.py
def user_list(request):
"""用户管理"""
return render(request, 'user_list.html')
user_list.html
直接copydepart_list.html ,修改一下文字部分即可
{% extends 'layout.html' %}
{% block content %}
{# 用户列表 #}
<div class="container">
<div style="margin-bottom: 10px">
<a class="btn btn-success" href="/depart/add/" >
{# 可以添加一个 target="_blank" : 使页面在新页面打开,如果不设置,会在原页面打开(这里我们还是在当前页面打开) #}
<span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
新建用户
</a>
{#新建一个 depart_add.html , 用来写新建部门界面#}
</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>ID</th>
<th>名称</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<th>123</th>
<td>321</td>
<td>
<a class="btn btn-primary btn-xs" href="#">编辑</a>
<a class="btn btn-danger btn-xs" href="#">删除</a>
</td>
</tr>
{# {% for obj in queryset %}#}
{# <tr>#}
{# <th>{{ obj.id }}</th>#}
{# <td>{{ obj.title }}</td>#}
{# <td>#}
{# <a class="btn btn-primary btn-xs" href="/depart/{{ obj.id }}/edit/">编辑</a>#}
{# btn ==> 添加btn的按钮#}
{# btn-primary ==> 蓝色按钮(按钮的样式)#}
{# btn-xs ==> 这会让按钮看起来特别小(按钮大小)#}
{# <a class="btn btn-danger btn-xs" href="/depart/detele/?nid={{ obj.id }}">删除</a>#}
{# </td>#}
{# </tr>#}
{# {% endfor %}#}
</tbody>
</table>
</div>
</div>
{% endblock %}
效果展示:
导航栏的跳转效果
任务:点击导航栏的“用户管理”,即可跳转到用户管理界面
修改导航栏
layout.html
<ul class="nav navbar-nav">
<li><a href="/depart/list/">部门管理</a></li>
<li><a href="/user/list/">用户管理</a></li>
<li><a href="#">Link</a></li>
</ul>
这样就完成了跳转功能
用户管理表格设计
user_list.html
<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>
<tr>
<th>123</th>
<td>321</td>
<td>321</td>
<td>321</td>
<td>321</td>
<td>321</td>
<td>321</td>
<td>321</td>
<td>
<a class="btn btn-primary btn-xs" href="#">编辑</a>
<a class="btn btn-danger btn-xs" href="#">删除</a>
</td>
</tr>
效果展示:
向表格添加用户数据
回顾一下我们之前设计的用户管理表
写点sql语句,添加用户:
insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("韩超","666",23,100.68,"2020-01-11",2,1);
insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("刘东","123",23,100.68,"2010-11-11",1,1);
insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("朱虎飞","999",33,9900.68,"2021-05-11",1,1);
问题:
mysql> insert into app01_userinfo(name,password,age,account,create_time,gender,depart_id) values("刘东","123",23,100.68,"2010-11-11",1,4);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`employee`.`app01_userinfo`, CONSTRAINT `app01_userinfo_depart_id_e22e0907_fk_app01_department_id` FOREIGN KEY (`depart_id`) REFERENCES `app01_department` (`id`))
输入第二个数据报错:我们收到错误"无法添加或更新子行:外键" 约束失败"。
原因:在插入含有外键的表中,若要插入外键为空时,直接insert则会报错,注意他最后一个参数是【4】,我们定义的【1】是【男】、【2】是【女】,【4】在范围之外
我们修改一下views.py看一下效果:
def user_list(request):
"""用户管理"""
queryset = models.UserInfo.objects.all()
for obj in queryset:
print(obj.id, obj.name, obj.accoun, obj.create_time.strftime("%Y-%m-%d"), type(obj.create_time))
return render(request, 'user_list.html')
PS:关于入职时间
效果展示:
运行django项目,跳转到http://127.0.0.1:8000/user/list/
Django version 3.2.6, using settings 'employeemanage.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
6 韩超 100.68 2020-01-11 <class 'datetime.datetime'>
7 刘东 100.68 2010-11-11 <class 'datetime.datetime'>
8 朱虎飞 9900.68 2021-05-11 <class 'datetime.datetime'>
如何获取关联的数据呢?
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"), type(obj.create_time))
temp = models.Department.objects.filter(id=obj.depart_id).first()
print(temp.title)
print(obj.depart_id)
print(obj.depart.title)
return render(request, 'user_list.html')
效果展示:
6 韩超 100.68 2020-01-11 <class 'datetime.datetime'>
IT部门
1
IT部门
7 刘东 100.68 2010-11-11 <class 'datetime.datetime'>
IT部门
1
IT部门
8 朱虎飞 9900.68 2021-05-11 <class 'datetime.datetime'>
IT部门
1
IT部门
然后就是把数据库的数据传到前端了
user_list.html
<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.get_gender_display() }}</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>
注意区别Python语法与模板语法:
{# 模板语法是不能加括号的,需要加括号时,他会自动帮你加上 #}
{# <td>{{ obj.create_time.strftime("%Y-%m-%d") }}</td>#}
{# <td>{{ obj.get_gender_display() }}</td>#}
<td>{{ obj.create_time|date:"Y-m-d"}}</td>
<td>{{ obj.get_gender_display }}</td>
<td>{{ obj.depart.title }}</td>
可能遇到的问题:
Exception Type: TemplateSyntaxError
Exception Value:
Could not parse the remainder: ': "Y-m-d"' from 'obj.create_time|date: "Y-m-d"'
原因:
<td>{{ obj.create_time|date:"Y-m-d"}}</td> 对于"Y-m-d" ,其前面一个空格都不能有,否则就会报上述错误,格式要求很严格
前端效果展示:
3、新建用户(原始方法)
三种方式
-
原始方法思路:麻烦 -
Django组件
- Form组件(简便)
- ModelForm组件(最简便)
我们首先体验一下用原始的方式实现新增用户,下一节中再使用Django组件
基础效果
修改href
<a class="btn btn-success" href="/user/add/">
{# 可以添加一个 target="_blank" : 使页面在新页面打开,如果不设置,会在原页面打开(这里我们还是在当前页面打开) #}
<span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
新建用户
</a>
path('user/add/', views.user_add),
特别是“性别”和“部门”俩属性,需要特殊处理,我们输入值只能是已有的选项
{% 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="姓名" >
</div>
<div class="form-group">
<label>密码</label>
<input type="text" class="form-control" placeholder="密码">
</div>
<div class="form-group">
<label>年龄</label>
<input type="text" class="form-control" placeholder="年龄">
</div>
<div class="form-group">
<label>余额</label>
<input type="text" class="form-control" placeholder="余额">
</div>
<div class="form-group">
<label>入职时间</label>
<input type="text" class="form-control" placeholder="入职时间">
</div>
<div class="form-group">
<label>性别</label>
{#<input type="text" class="form-control" placeholder="性别">#}
<select class="form-control">
<option value="1">男</option>
<option value="2">女</option>
</select>
</div>
<div class="form-group">
<label>部门</label>
{# <input type="text" class="form-control" placeholder="部门"> #}
<select class="form-control">
<option value="1">IT部门</option>
<option value="2">媒体企划</option>
</select>
</div>
<button type="submit" class="btn btn-primary">提交</button>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
效果展示:
优化
前面,对于“部门”我们是写死的,这样很不好,部门数量太多、部门关联的ID变化、新增部门等等情况都会引来麻烦
def user_add(request):
"""添加用户"""
context = {
'gender_choice' : models.UserInfo.gender_choices,
'depart_list' : models.Department.objects.all(),
}
return render(request, "user_add.html", context)
<div class="form-group">
<label>部门</label>
{# <input type="text" class="form-control" placeholder="部门"> #}
<select class="form-control">
{# <option value="1">IT部门</option>#}
{# <option value="2">媒体企划</option>#}
{# value 的值必须与数据库相对应 #}
{% for item in depart_list %}
<option value="{{ item.id }}">{{ item.title }}</option>
{% endfor %}
</select>
</div>
完成提交(数据库)
老样子
- (1)对前端各个信息一个一个获取
- (2)后端( views.py / user_add() )中接收前端提交的数据(POST)
- (3)传入数据库
- (4)返回用户列表界面
在最后加【name】属性
<div class="form-group">
<label>姓名</label>
<input type="text" class="form-control" placeholder="姓名" name="user"/>
</div>
<div class="form-group">
<label>密码</label>
<input type="text" class="form-control" placeholder="密码" name="pwd"/>
</div>
<div class="form-group">
<label>年龄</label>
<input type="text" class="form-control" placeholder="年龄" name="age"/>
</div>
<div class="form-group">
<label>余额</label>
<input type="text" class="form-control" placeholder="余额" name="ac"/>
</div>
<div class="form-group">
<label>入职时间</label>
<input type="text" class="form-control" placeholder="入职时间" name="ctime"/>
</div>
- (2)后端( views.py / user_add() )中接收前端提交的数据(POST)
将用户的一堆属性一个一个获取
user = request.POST.get('user')
pwd = request.POST.get('pwd')
age = request.POST.get('age')
account = request.POST.get('ac')
ctime = request.POST.get('ctime')
gender = request.POST.get('gd')
depart_id = request.POST.get('dp')
models.UserInfo.objects.create(name=user, password=pwd, age=age,
account=account, create_time=ctime,
gender=gender, depart_id=depart_id)
return redirect("/user/list/")
user_add.html
{% extends 'layout.html' %}
{% block content %}
<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="user"/>
</div>
<div class="form-group">
<label>密码</label>
<input type="text" class="form-control" placeholder="密码" name="pwd"/>
</div>
<div class="form-group">
<label>年龄</label>
<input type="text" class="form-control" placeholder="年龄" name="age"/>
</div>
<div class="form-group">
<label>余额</label>
<input type="text" class="form-control" placeholder="余额" name="ac"/>
</div>
<div class="form-group">
<label>入职时间</label>
<input type="text" class="form-control" placeholder="入职时间" name="ctime"/>
</div>
<div class="form-group">
<label>性别</label>
<select class="form-control" name="gd">
{% for item in gender_choices %}
<option value="{{ item.0 }}">{{ item.1 }}</option>
{% endfor %}
</select>
</div>
<div class="form-group">
<label>部门</label>
<select class="form-control" name="dp">
{% for item in depart_list %}
<option value="{{ item.id }}">{{ item.title }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary">提 交</button>
</form>
</div>
</div>
</div>
{% endblock %}
views.py
def user_add(request):
"""添加用户(原始方式)"""
if request.method == "GET":
context = {
'gender_choices': models.UserInfo.gender_choices,
"depart_list": models.Department.objects.all()
}
return render(request, 'user_add.html', context)
user = request.POST.get('user')
pwd = request.POST.get('pwd')
age = request.POST.get('age')
account = request.POST.get('ac')
ctime = request.POST.get('ctime')
gender = request.POST.get('gd')
depart_id = request.POST.get('dp')
models.UserInfo.objects.create(name=user, password=pwd, age=age,
account=account, create_time=ctime,
gender=gender, depart_id=depart_id)
return redirect("/user/list/")
4、Django组件:Form 和 ModelForm
我们刚了解了用原始方式实现“新建用户”,我们先回顾一下
新建用户:
4.1、初识Form
我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。
与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。
Django form组件就实现了上面所述的功能。
总结一下,其实form组件的主要功能如下:
- 生成页面可用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入内容
1、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)
def user_add(request):
if request.method == "GET":
form = MyForm()
return render(request, 'user_add.html',{"form":form})
2、user_add.html
以往要写一堆input,一个input还要一堆参数,现在利用Form:
<form method="post">
{{ form.user }}
{{ form.pwd }}
{{ form.email }}
</form>
其实,还能再简便一点,写个循环(循环form中所有的字段):
<form method="post">
{% for field in form%}
{{ field }}
{% endfor %}
</form>
对比采用原始方法:
但这样class MyForm(Form)中的内容还是太繁琐了,一个属性一个属性的去定义
细心的同学可能想到,我们在models.py中已经干过这些事情了
4.2、ModelForm(推荐)
0、models.py
class UserInfo(models.Model):
""" 员工表 """
name = models.CharField(verbose_name="姓名", max_length=16)
password = models.CharField(verbose_name="密码", max_length=64)
age = models.IntegerField(verbose_name="年龄")
account = models.DecimalField(verbose_name="账户余额", max_digits=10, decimal_places=2, default=0)
create_time = models.DateTimeField(verbose_name="入职时间")
depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE)
gender_choices = (
(1, "男"),
(2, "女"),
)
gender = models.SmallIntegerField(verbose_name="性别", choices=gender_choices)
1、views.py
class MyForm(ModelForm):
xx = form.CharField*("...")
class Meta:
model = UserInfo
fields = ["name","password","age","xx"]
def user_add(request):
if request.method == "GET":
form = MyForm()
return render(request, 'user_add.html',{"form":form})
2、user_add.html
<form method="post">
{% for field in form%}
{{ field }}
{% endfor %}
</form>
<form method="post">
{{ form.user }}
{{ form.pwd }}
{{ form.email }}
</form>
5、新建用户(ModelForm)
补充知识:
class Foo(object):
def __str__(self):
return "Hello World"
obj = Foo()
print(obj)
Hello World
进程已结束,退出代码为 0
from django.forms import ModelForm
"""新建用户(ModelForm版本)"""
class MyForm(ModelForm):
class Meta:
model = models.UserInfo
fields = ["name", "password", "age", 'account', 'create_time', "gender", "depart"]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for name, field in self.fields.items():
field.widget.attrs = {"class": "form-control", "placeholder": field.label}
def user_add(request):
form = MyForm()
return render(request, 'user_add.html', {"form": form})
{% extends 'layout.html' %}
{% block content %}
<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 %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">提 交</button>
</form>
</div>
</div>
</div>
{% endblock %}
问题:
原因: Department object(1) 是 models.py 中 Department 的对象
让他正常显示部门名称,解决方法就是本节开头说的,利用__str__ 魔法函数
models.py
def __str__(self):
return self.title
depart = models.ForeignKey(verbose_name="部门", to="Department", to_field="id", on_delete=models.CASCADE)
效果展示:
将数据储存至数据库:
def user_add(request):
if request.method == "GET":
form = MyForm()
return render(request, 'user_add.html', {"form": form})
form = MyForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
form.save()
return redirect("/user/list/")
else:
print(form.errors)
效果展示:
错误提示
{% extends 'layout.html' %}
{% block content %}
<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> {# novalidate : 关闭浏览器帮我们做的校验,用自己的 #}
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<label>{{ field.label }}</label>
{{ field }}
<span style="color: red;">{{ field.errors.0 }}</span> {# 错误信息可能有很多,我们只显示第0个就好了 #}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">提 交</button>
</form>
</div>
</div>
</div>
{% endblock %}
def user_add(request):
if request.method == "GET":
form = MyForm()
return render(request, 'user_add.html', {"form": form})
form = MyForm(data=request.POST)
if form.is_valid():
print(form.cleaned_data)
form.save()
return redirect("/user/list/")
return render(request, 'user_add.html', {"form": form})
把多余的注释都去掉
def user_add(request):
if request.method == "GET":
form = MyForm()
return render(request, 'user_add.html', {"form": form})
form = MyForm(data=request.POST)
if form.is_valid():
form.save()
return redirect("/user/list/")
return render(request, 'user_add.html', {"form": form})
- 效果展示:
提交空数据(这里的错误提示都是ModelForm帮我们默认做好的)
我们可以自己自定义一下:
比如,名字限制在三位以内
class MyForm(forms.ModelForm):
name = forms.CharField(min_length=3, label="用户名")
报错改为中文:
LANGUAGE_CODE = 'zh-hans'
-
效果展示:
|