赞
踩
主题:员工管理系统
参考:最新Python的web开发全家桶(django+前端+数据库)_哔哩哔哩_bilibili
新建项目,创建注册app,具体参见前两节,这里只展示在【models.py】中定义好的两个类,即对应着数据库中的两个数据表
#【models.py】 from django.db import models # Create your models here. class Department(models.Model): # 部门表 title = models.CharField(verbose_name='部门标题',max_length=32) #verbose_name:对当前列的注解,可写可不写,写了便于理解 def __str__(self): # 应对使用ModelForm时,输出部门对象无法输出title的情况 [1] return self.title class UserInfo(models.Model): # 员工表 name = models.CharField(verbose_name='姓名',max_length=16) # [2] 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) # 分别定义m,d create_time = models.DateTimeField(verbose_name="入职时间") # django中的约束:在填写性别时只能填写0或1 [3] gender_choices=( (0, "女"), (1, '男') ) gender = models.SmallIntegerField(verbose_name="性别",choices=gender_choices) # 外键设置 [4] depart = models.ForeignKey(to="Department", to_field="id", on_delete=models.CASCADE) # to:关联的表,to_field关联表的列 # django自动的外键命名方式:设置列名 + ‘_id’ , 如:depart_id # 设置关联表相关数据删除时的处理方式: # 1. 级联删除:depart = models.ForeignKey(to="Department",to_field="id",on_delete=models.CASCADE) # 2. 置空:depart = models.ForeignKey(to="Department",to_field="id",null=True,blank=True,on_delete=models.SET_NULL)
【注意】
在部门表中,需要重写类的__str__()
函数,以保证在直接print对象时,可以输出指定的内容(这里是部门名称),以解决后面在form表单输出时直接输出部门对象导致无法输出部门名称的问题 [1]
在员工表中的成员定义中的verbose_name
字段,是对当前成员的解释信息,后面使用ModelForm的时候会用到
在员工表中,在性别列的定义中,我们可以使用choice
字段,来完成自定义的映射和数据约束,即使用一个以双元素元组为元素的元组定义映射,然后在声明成员时将这个元组当作choice
字段的值 [2]
在员工表中的“所属部门”需要和部门表进行关联映射,所以需要设置为外键以满足数据约束(员工表中数据必须在部门表中存在),设置方式即
外键名 = models.ForeignKey(to="关联表名", to_field="关联表的列(一般是主键)", on_delete=关联表删除数据时的处理方式)
随便找的一个巨丑的模板:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>用户管理系统</title> <style> /* 添加一些基本样式,可以根据需要进行自定义 */ body { font-family: Arial, sans-serif; } .navbar { background-color: #333; overflow: hidden; } .navbar a { float: left; display: block; color: white; text-align: center; padding: 14px 16px; text-decoration: none; } .navbar a:hover { background-color: #ddd; color: black; } .title { text-align: center; padding: 20px; background-color: #f4f4f4; } table { width: 100%; border-collapse: collapse; } th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; } th { background-color: #f2f2f2; } .btn { padding: 4px 8px; border: none; cursor: pointer; } .btn-edit { background-color: #4CAF50; color: white; } .btn-delete { background-color: #f44336; color: white; } .input-container { text-align: center; padding: 20px; } .input-field { padding: 8px; } </style> </head> <body> <div class="title"> <h1>用户管理系统</h1> </div> <div class="navbar"> <a href="user_list.html">用户列表</a> <a href="department_list.html">部门列表</a> </div> <div class="title"> <h2>用户列表</h2> </div> <table> <tr> <th>ID</th> <th>部门</th> <th>操作</th> </tr> <tr> <td>1</td> <td>销售部</td> <td> <button class="btn btn-edit">编辑</button> <button class="btn btn-delete">删除</button> </td> </tr> <tr> <td>2</td> <td>人力资源部</td> <td> <button class="btn btn-edit">编辑</button> <button class="btn btn-delete">删除</button> </td> </tr> <!-- 添加更多行... --> </table> <div class="input-container"> <h2>添加新部门</h2> <input type="text" class="input-field" placeholder="部门名称"> <button class="btn btn-submit">提交</button> </div> </body> </html>
大概是这样的:
但是有导航栏,功能齐全,我们想让后面写得所有页面都有导航栏,又不想每个页面都把这份代码写一遍(而且那样也不好修改),于是我们可以使用django的模板继承功能。
在app【templates】目录下,编写【layout.html】文件(当然也可以不叫这个名)
<!-- 【layout.html】 --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> {% block title %} {% endblock %} <style> /* 添加一些基本样式,可以根据需要进行自定义 */ body { font-family: Arial, sans-serif; } .navbar { background-color: #333; overflow: hidden; } .navbar a { float: left; display: block; color: white; text-align: center; padding: 14px 16px; text-decoration: none; } .navbar a:hover { background-color: #ddd; color: black; } .title { text-align: center; padding: 20px; background-color: #f4f4f4; } a:link { color: white; background-color: transparent; text-decoration: none; } a:visited { color: white; background-color: transparent; text-decoration: none; } a:hover { color: white; background-color: transparent; text-decoration: underline; } a:active { color: white; background-color: transparent; text-decoration: underline; } table { width: 100%; border-collapse: collapse; } th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; } th { background-color: #f2f2f2; } .btn { padding: 4px 8px; border: none; cursor: pointer; } .btn-edit { background-color: #4CAF50; color: white; } .btn-delete { background-color: #f44336; color: white; } .input-container { text-align: center; padding: 20px; } .input-field { padding: 8px; } </style> </head> <body> <div class="title"> <h1>员工管理系统</h1> </div> <div class="navbar"> <a href="/depart/list/">部门列表</a> <a href="/user/list/">用户列表</a> </div> {% block content %} {% endblock %} <div class="title"> <h2>欢迎访问员工管理系统</h2> </div> </body> </html>
注意,在每个页面都要保留的部分和样式表,我们都原封不动的保留,但是在每个页面需要特异性的地方,我们使用格式:
{% block 名称 %}
{% endblock %}
进行占位,这样,【layout.html】就成了挖好了空的“代码模板”,供我们后续使用
在编写特定页面时,我们只需要继承模板页面,然后只需要填写在挖空部分的代码即可
<!-- 【depart_list.html】 --> {% extends 'layout.html' %} <!-- 使用此代码继承 layout.html --> {% block title %} <!-- 在占位符之间加入需要的代码 --> <title>部门列表</title> {% endblock %} {% block content %} <h2 class="title">部门列表</h2> <button><a href="/depart/add/">添加部门</a></button> <table> <tr> <th>ID</th> <th>部门</th> <th>操作</th> </tr> <tbody> {% for obj in data_list %} <tr> <td>{{ obj.id }}</td> <td>{{ obj.title }}</td> <td> <button class="btn btn-edit" ><a href="/depart/{{ obj.id }}/update/">编辑</a></button> <button class="btn btn-delete"><a href="/depart/delete/?nid={{ obj.id }}">删除</a></button> </td> </tr> {% endfor %} </tbody> </table> {% endblock %}
这样,我们就可以在多种不同页面中使用同一套布局和样式
<!-- 【depart_add.html】 --> {% extends 'layout.html' %} {% block title %} <title>添加部门</title> {% endblock %} {% block content %} <h2 class="title">添加部门</h2> <div class="input-container"> <form method="post" ><!--post当前页面时,action可以不写--> {% csrf_token %} <!-- 别忘了!! --> <input type="text" name="depart_name" class="input-field" placeholder="部门名称"> <button class="btn btn-submit">提交</button> </form> </div> {% endblock %}
关于页面数据表的增加与删除,前面的学习笔记中都有记录,这里不再赘述,具体代码如下:
# 【urls.py】
from django.urls import path
from app01 import views
urlpatterns = [
#path('admin/', admin.site.urls),
path('depart/list/', views.depart_list),
path('depart/add/', views.depart_add),
path('depart/delete/', views.depart_del),
#格式化的地址输入,/depart/和/update/之间必须有一个int型的数值
path('depart/<int:nid>/update/', views.depart_upd),
]
# 【views.py】 from django.shortcuts import render, redirect from app01.models import Department,UserInfo # Create your views here. def depart_list(request): ## 部门列表 data_list = Department.objects.all() return render(request,'depart_list.html',{'data_list':data_list}) def depart_add(request): if request.method == 'GET': return render(request,'depart_add.html') depart_name = request.POST.get("depart_name") Department.objects.create(title=depart_name) return redirect('/depart/list/') def depart_del(request): nid = request.GET.get('nid') Department.objects.filter(id=nid).delete() return redirect("/depart/list/") def depart_upd(request,nid): # 多传一个nid的参数 if request.method == 'GET': row_obj = Department.objects.filter(id=nid).first() return render(request,"depart_update.html",{"row_obj": row_obj}) title = request.POST.get("depart_name") Department.objects.filter(id=nid).update(title=title) return redirect("/depart/list/")
这里主要新增了一个更改部门名称的功能,首先,修改数据和新增数据需要的操作和输入基本相同,其页面在新增部门的页面基础上稍作修改即可。主要是获取到修改部门的id,然后根据id在输入框中显示出部门名称。
<!-- 【depart_update.html】 --> {% extends 'layout.html' %} {% block title %} <title>编辑部门</title> {% endblock %} {% block content %} <h2 class="title">编辑部门</h2> <div class="input-container"> <form method="post" ><!--post当前页面时,action可以不写--> {% csrf_token %} <!-- 别忘了!! --> <input type="text" name="depart_name" class="input-field" placeholder="部门名称" value="{{ row_obj.title }}"> <button class="btn btn-submit">提交</button> </form> </div> {% endblock %}
在修改部门的数据传递上,除去之前学到的使用url后面加上 ’ ?nid=xx ’ 的方式,我们也可以使用另外一种格式化在地址中加入数值的方式,即在【urls.py】的path中将地址写为:
path('depart/<int:nid>/update/', views.depart_upd),
/<int:nid>/
代表url在当前位置必须加入一个 int 型数值的参数,参数名为 nid。
而相应的,在【views.py】定义的函数中,我们不需要使用 GET 方法获取nid,而是直接在函数参数中写上nid,即可直接获得nid的值。
def depart_upd(request,nid):
....
在部门列表页面【depart_list.html】中通过url传递数据时,按照【urls.py】中定义的格式在相应位置写入nid的值即可
<button class="btn btn-edit" ><a href="/depart/{{ obj.id }}/update/">编辑</a></button>
上面部门管理时进行数据管理的缺点:
- 用户提交数据没有校验,发生错误应该有错误提示
- 页面上每个字段都要独立写一遍
- 数据关联全凭手动
以新建用户为例,使用ModelForm组件:
#【views.py】 from django import forms from app01 import models class UserModelForm(forms.ModelForm): # 定义数据约束(默认非空,无需设置) age = forms.IntegerField(min_value=1) #重写age,限制其输入必须为正数 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():#修改构造函数,给所有输入框加上样式表和其他属性(如果有想用不同样式的,特判name即可) field.widget.attrs = {'class':'input-field','placeholder':field.label} def user_add(request): if request.method == 'GET': form = UserModelForm() return render(request,'user_add.html',{"form":form}) # 提交数据校验 form = UserModelForm(data=request.POST) if form.is_valid(): #数据合法,一键保存到数据库 form.save() #直接保存到form对应那个的表里面 return redirect('/user/list/') else: # 校验失败,在页面显示错误信息 return render(request,'user_add.html',{"form":form})
由上面可以看到,在【views.py】页面,除去编写url对应函数外,需要声明一个继承自ModelForm的类,其中可以设置数据约束、选择待编辑列名和输入表单样式属性等,在函数部分,直接将form对象传入html文件即可。
而在获取到用户输入的表单信息后,可以进行数据合法性判断,若数据合法,可以使用form.save()
一键保存到数据库,若不合法,返回错误信息到页面即可。
<!-- 【user_add.html】 --> {% extends 'layout.html' %} {% block title %} <title>添加用户</title> {% endblock %} {% block content %} <h2 class="title">添加用户</h2> <div class="input-container"> <form method="post" ><!--post当前页面时,action可以不写--> {% csrf_token %} <!-- 别忘了!! --> {% for field in form %} <div> {{ field.label }} : {{ field }} <span>{{ field.errors.0 }}</span><!-- 显示错误信息!! --> <br><br><br> </div> {% endfor %} <button class="btn btn-edit">提交</button> </form> </div> {% endblock %}
在html文件中,直接将form对象进行渲染,其中field.lable
是之前在【models.py】定义列名时写下的verbose_name
字段,field
会直接打印相应对象(所以外键需要设置字符输出)
此外,若编辑用户时输入错误或不符合数据要求,还可以通过field.errors
返回相应的错误信息 对输入者进行提示。
# 【views.py】
def user_upd(request,nid):
row_obj = UserInfo.objects.filter(id=nid).first()
if request.method == 'GET':
# 先获取nid对应的数据
form = UserModelForm(instance=row_obj) # 表达自动显示默认值
return render(request,'user_update.html',{"form":form})
form = UserModelForm(data=request.POST,instance=row_obj)# 只有加上instance才能正确修改
if form.is_valid():
form.save()
return redirect("/user/list/")
return render(request,'user_update.html',{"form":form})
用户编辑页面和用户添加页面大致相同,需要注意的是在显示表单时,我们可以通过instance
字段来使用目前获得到的数据库数据对表单进行填充
在获取到用户使用POST上传的编辑好的信息后,也是需要instance
字段来保证正确修改(不然就会在数据库中直接新建一个用户,而不是修改)
<!-- 【user_update.html】 --> {% extends 'layout.html' %} {% block title %} <title>编辑用户</title> {% endblock %} {% block content %} <h2 class="title">编辑用户</h2> <div class="input-container"> <form method="post" ><!--post当前页面时,action可以不写--> {% csrf_token %} <!-- 别忘了!! --> {% for field in form %} <div> {{ field.label }} : {{ field }} <span>{{ field.errors.0 }}</span><!-- 显示错误信息!! --> <br><br><br> </div> {% endfor %} <button class="btn btn-edit">提交</button> </form> </div> {% endblock %}
# 【urls.py】
urlpatterns = [
#【之前的那一部分】...
path('user/list/', views.user_list),
path('user/add/', views.user_add),
path('user/delete/', views.user_del),
# 格式化的地址输入,/depart/和/update/之间必须有一个int型的数值
path('user/<int:nid>/update/', views.user_upd),
]
【user_list.html】与部门列表相差无几,可以注意的是使用了choice=gender_choice
后需要使用get_gender_display
来进行自动映射,而外键可以直接使用外键成员名即可完成自动映射
<!-- 【user_list.html】 --> {% extends 'layout.html' %} {% block title %} <title>员工列表</title> {% endblock %} {% block content %} <h2 class="title">员工列表</h2> <button class="btn btn-edit"><a href="/user/add/">⊕添加员工</a></button> <table> <tr> <th>ID</th> <th>姓名</th> <th>密码</th> <th>年龄</th> <th>余额</th> <th>创建时间</th> <th>性别</th> <th>部门</th> <th>操作</th> </tr> <tbody> {% for obj in data_list %} <tr> <td>{{ obj.id }}</td> <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> <!-- 使用gender_choices自动映射 --> <td>{{ obj.depart}}</td><!-- 直接写外键成员名就可以自动映射 --> <td> <button class="btn btn-edit" ><a href="/user/{{ obj.id }}/update/">编辑</a></button> <button class="btn btn-delete"><a href="/user/delete/?nid={{ obj.id }}">删除</a></button> </td> </tr> {% endfor %} </tbody> </table> {% endblock %}
列表和删除功能与部门做法一样,不再赘述
# 【views.py】
def user_list(request):
data_list = UserInfo.objects.all()
return render(request,'user_list.html',{'data_list':data_list})
def user_del(request):
nid = request.GET.get('nid')
UserInfo.objects.filter(id=nid).delete()
return redirect("/user/list/")
效果:
编辑用户时,可以做到输入检查
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。