当前位置: 首页 > news >正文

Django入门教程——员工数据管理

第四章 员工数据管理

教学目的

  • 了解模型表单创建表单编辑界面的意义
  • 理解模版表单的常用属性和使用方法
  • 理解通过模型表单实现数据的添加和编辑方法
  • 理解表单验证的方法

从模型创建表单

模型表单简介

如果您正在构建一个数据库驱动的应用程序,那么您很有可能会用到与Django模型密切相关的表单。Django 提供了一个辅助类让你可以从一个 Django 模型创建一个表单,就是将Model与Form进行绑定,Form有自动生成表单的作用。参考:https://docs.djangoproject.com/zh-hans/5.1/topics/forms/modelforms/

每个生成的表单字段的属性设置如下:

  • 如果模型字段设置了 blank=True ,那么表单字段的 required 属性被设置为 False ,否则required=True 。
  • 表单字段的 label 设置为模型字段的 verbose_name ,并且首字母大写。
  • 如果模型字段设置了 choices ,那么表单字段的 widget 会被设置为 Select ,其选项来自模型字段的 choices

员工添加表单

  1. 创建forms文件夹,用于存放表单类

  2. 创建employee_form.py,用于存放员工相关表单。

    • 创建表单类

      from django import forms
      from archives.models import Employee
      class employee_add_form(forms.ModelForm):class Meta:model = Employeefields = ['name','depart','job_number','gender','birthday','phone']
      
    • 人员添加视图函数

      # 员工添加
      def employee_add(request):if request.method == "GET":form = employee_form.employee_add_form()for field in form:print(field,"==字段控件")print(field.label,"==字段标签")print(field.name,"==字段名称")print(field.field.required,"==字段是否必输")return render(request,"archives/employee_add.html",{"form":form,'title':'添加员工'})
      
    • 人员添加模板页面

      {%extends 'common/layout.html'%}
      {% block head%}
      <div class="layui-card-header" style="font-weight: bold;">{{title}}</div>
      {% endblock %}
      {% block content %}
      <form class="layui-form"  method="post" novalidate>{% csrf_token %}{% for field in form %}<div class="layui-form-item"><label class="layui-form-label">{{ field.label }}:</label><div class="layui-input-block">{{ field }}</div></div>{%endfor%}<div class="layui-form-item"><div class="layui-input-block"><button type="submit" class="layui-btn" >确认</button></div></div>
      </form>
      {% endblock %}
      

    {% for field in form %} 可以循环输出表单所有元素,{{ field }}为对应的控件,{{ field.label }}为模型字段的 verbose_name

    model 内部类Meta的model属性设置了表单对应的数据模型

    fields属性决定了表单中的元素以及元素的显示顺序,fields = '__all__'可以设置为模型中的所有字段

    widgets属性是一个字典,定制界面显示方式(文本框、选择框)

页面样式优化

  1. 给表单字段批量添加layui样式,class="layui-input",修改表单对象

    from django import forms
    from archives.models import Employee
    class employee_add_form(forms.ModelForm):class Meta:model = Employeefields = ['name','depart','job_number','gender','birthday']def __init__(self,*args,**kwargs):super().__init__(*args,**kwargs)for name,field in self.fields.items():field.widget.attrs={"class":"layui-input","placeholder":"输入"+field.label}
    
  2. 对必须输入字段前面加*

    • 定义标签样式表

       /* 必须字段 */.label-required-next:after {top: 6px;right: 5px;color: red;content: '*';position: absolute;margin-left: 4px;font-weight: 700;line-height: 1.8em;}
      

      参考:https://www.runoob.com/cssref/sel-after.html

      :after 选择器:向选定元素的最后子元素后面插入内容。使用content 属性来指定要插入的内容。

    • 修改表单模板页面

      <form class="layui-form"  method="post" novalidate>{% csrf_token %}{% for field in form %}<div class="layui-form-item">{% if field.field.required %}<label class="layui-form-label label-required-next">{{ field.label }}:</label>{% else %}<label class="layui-form-label">{{ field.label }}:</label>{% endif %}<div class="layui-input-block">{{ field }}</div></div>{% endfor %}<div class="layui-form-item"><div class="layui-input-block"><button type="submit" class="layui-btn" lay-submit>确认提交</button></div></div>
      </form>
      

数据保存

form = employee_form.employee_add_form(data=request.POST)
if form.is_valid():print(form.cleaned_data) #打印form提交的所有数据form.instance.hiredate=datetime.now()form.save()
else:print(form.errors) #打印form提交的错误信息
return HttpResponse("添加员工")

data=request.POST 创建表单,数据值为提交的数据

is_valid() 调用表单的这个函数实现表单的验证,验证后的数据可以通过cleaned_data获取数据字典,验证没有通过通过errors获得错误信息

instance 获取当前表单的模型对象,form.instance.hiredate=datetime.now()设置模型中入职时间为当前时间

save()方法实现数据的保存,可以是添加或者修改

表单对象的属性和方法总结:

  • is_bound——是否已经绑定数据
  • is_valid()——表单是否已经通过验证
  • cleaned_data——访问表单验证后的数据
  • as_p()/as_ul()/as_table()——渲染表单
  • errors——表单验证后的错误信息
  • fields——表单中的字段
  • initial——初始化数据

字段常用的核心参数:

  • required——是否为必填,默认为True
  • label——label标签(输入框前的文字描述)
  • initial——初始化数据
  • attrs——定义表单对象的属性
  • widget——定制界面显示方式(文本框、选择框)
  • help_text——帮助文字
  • error_messages——覆盖字段引发异常后的错误显示
  • localize——本地化,根据用户所在地区格式进行显示
  • disabled——禁用表单,界面上不可操作
  • has_changed()——值是否发生了改变

Django的内置字段:

文本/字符串:

  • CharField——字符串输入
  • TextInput——文本框输入
  • DateInput——日期输入
  • EmailField——邮件地址输入
  • URLField——URL地址输入
  • UUIDField——uuid字符串输入

数值(整数、小数)

  • FloatField——浮点数输入
  • IntegerField——整数输入
  • DecimalField——小数输入(更精确)

选择

  • ChoiceField——单选
  • MultipleChoiceField——多选
  • TypedChoiceField——高级选择(支持结果转换类型)

员工信息展示页面

  1. 员工信息展示页面

    {%extends 'common/layout.html'%}
    {% block content %}
    <a href="/employee/add/" class="layui-btn">添加员工</a>
    <table class="layui-table" lay-even><thead><tr><th>工号</th><th>姓名</th><th>部门</th><th>性别</th><th>入职时间</th><th>操作</th></tr> </thead><tbody>{% if not data_list %}<tr><td colspan="6" style="color: #CCC; text-align: center;font-size: 10px;">---------暂无数据---------</td></tr>{%endif%}{% for obj in data_list %}<tr><td>{{ obj.job_number }}</td><td>{{ obj.name }}</td><td>{{ obj.depart.name }}</td><td>{{ obj.get_gender_display }}</td><td>{{ obj.hiredate }}</td><td><a href="#" class="layui-btn layui-btn-xs">编辑</a><a href="javascript:void(0)" class="layui-btn layui-btn-danger layui-btn-xs" lay-on="delete" data="{{obj.id}}">删除</a></td></tr>{% endfor %}</tbody>
    </table>
    {% endblock %}
    
    1. 选择性字段的显示

      • 后台显示:

        • 显示数据库保存的原始值:obj.字段名
        • 显示翻译后的文本:obj.get_字段名_display()
      • 前台(模板)显示

        • 显示数据库保存的原始值:obj.字段名
        • 显示翻译后的文本:obj.get_字段名_display 区别就是不要括号
    2. 级联表字段的显示

      • 显示原始值:obj.字段名
      • 显示翻译过的值:obj.字段名.关联表字段名
    3. 日期字段的显示

      • 后台格式化:obj.日期.strftime('%Y-%m-%d %H:%M:%S')
      • 前台模板:obj.日期|date:'Y-m-d' 注意没有%号
  2. 员工信息列表视图函数

    # 员工数据表格
    def employee_list(request):data_list = Employee.objects.all()return render(request,"archives/employee_list.html",{"data_list":data_list})
    
  3. 改造添加返回,以及表单数据验证

    if form.is_valid():print(form.cleaned_data) #打印form提交的所有数据form.instance.hiredate=datetime.now()form.save()return redirect("/employee/list/")
    else:print(form.errors) #打印form提交的错误信息return render(request,"archives/employee_add.html",{"form":form,'title':'添加员工'})
    
     <div class="layui-input-block">{{ field }}<span style="color: red">{{ field.errors.0 }}</span></div>
    
  4. 手机号码验证

    clean_xx()钩子函数,xx是表单中需要校验字段名称。

    • 校验顺序是class Metafileds列表的顺序。
    • form.is_valid()函数调用的时候会触发自定义的clean_xxx
    • 函数返回值,是最终表单验证后该字段的值
    def clean_phone(self):phone = self.cleaned_data['phone']if phone:if not re.match(r'^1[3-9]\d{9}$', phone):raise forms.ValidationError('请输入有效的手机号码。')    return phone
    

    正则表达式匹配规则

    • ^1 表示以1开头
    • [3-9] 限制了第二位数字的范围
    • \d{9} 表示接下来的9位都是数字
    • $ 表示整个模式到此为止,结束标志

    raise 是python中手动抛出异常的一种语句

    forms.ValidationError 是Django中验证错误提醒的语句,并且附加到该字段上

建立通用数据编辑模板

  1. 使用通用模板form_edit.html,改造部门添加编辑

  2. 使用layui组件实现出生日期的选择

    {%extends 'common/form_edit.html'%}
    {% block js %}
    <script>layui.use(function(){var laydate = layui.laydate;// 渲染laydate.render({elem: '#id_birthday'});})
    </script>
    {% endblock %}
    
  3. 修改出生日期的默认值

    ModelForm的构造函数参数:

    • data :用于接受通过表单提交的数据,一般为request.POST
    • instance:接收一个已经存在的 Model 实例,如果使用 instance 参数,save() 将更新这个实例;如果不使用,save() 将创建一个新的 Model 实例。
    • initial:接收一个字典,用于设置表单的初始值,没有设置将采用数据模型的默认值。
    if request.method == "GET":init_data = {'gender':2,'birthday':(datetime.now()-timedelta(days=365 * 22)).strftime("%Y-%m-%d"),}form = employee_form.employee_add_form(initial=init_data)
    
  4. 完善员工编辑功能

    # 员工数据编辑
    def employee_edit(request,nid):row_obj = Employee.objects.filter(id=nid).first()if request.method == "GET":form = employee_form.employee_add_form(instance=row_obj)return render(request,"archives/employee_add.html",{"form":form,'title':'编辑员工'})form = employee_form.employee_add_form(data=request.POST,instance=row_obj)if form.is_valid():form.save()return redirect("/employee/list/")print(form.errors,"===表单校验错误")return render(request,"archives/employee_add.html",{"form":form,'title':'编辑员工'})
    
  5. 修改表单,添加widgets属性,解决日期字段编辑格式错误问题

    widgets = {'birthday':forms.DateInput(format='%Y-%m-%d'),
    }
    
  6. 练习任务:完善家庭成员信息的展示、添加、编辑功能

复习类和星号运算符

基本语法:

#基类定义
class ClassName:class_suite  #类体#子类定义
class 派生类名(基类名):class_suite  #类体
class Employee:'所有员工的基类'empCount = 0def __init__(self, name, salary):self.name = nameself.salary = salaryEmployee.empCount += 1def __str__(self):return f"姓名 : {self.name}, 薪金: {self.salary}" def displayCount(self):print ("总共人员数:",Employee.empCount) def displayEmployee(self):print("姓名 : ",self.name,", 薪金: ",self.salary) employ1 = Employee("张三", 2000)
employ2 = Employee("李四", 3000)
employ1.displayEmployee()
employ2.displayEmployee()
employ1.displayCount()
print(employ2)
  • empCount 变量是一个类变量,它的值将在这个类的所有实例之间共享。你可以在内部类或外部类使用类名直接访问 Employee.empCount 访问。
  • 第一种方法__init__()方法是一种特殊的方法,被称为类的构造函数或初始化方法,当创建了这个类的实例时就会调用该方法。
  • __str__也是python类中一种特殊的方法,返回一个对实例描述的字符串。当执行print函数等打印实例时,调用该函数。
  • self 代表类的实例,self 在定义类的方法时是必须有的,虽然在调用时不必传入相应的参数。
  • 以self为前缀的变量都可以供类中的所有方法使用。
  • 方法重写:父类方法的功能不能满足你的需求,可以在子类重写你父类的方法。子类重写父类方法,方法的函数名要与父类相同
  • super()函数,可以通过子类调用父类中的函数
  • getattr(obj,'name')内置函数,获取obj对象的name属性值

星号运算符

在Python中,***是两个重要的运算符,它们具有不同的用途。

  • *(星号)用于解包列表,将其元素分配给函数的参数或在列表、元组等数据结构中进行拼接。
  • **(双星号)用于解包字典,将其键值对传递给函数的参数或在字典中进行拼接。
传递可变数量的参数(形参)
  1. 解包列表

    def sum_values(*args):total = 0for num in args:total += numreturn total
    result = sum_values(1, 2, 3, 4, 5)
    print("===调用函数结果:",result)  # 输出:15
    # 示例:拼接列表
    numbers1 = [1, 2, 3, 4, 5]
    numbers2 = [6, 7, 8]
    result = [*numbers1, *numbers2]  #实现列表合并
    print("===合并后的列表:",result)  # 输出:[1, 2, 3, 4, 5, 6, 7, 8]
    
  2. 解包字典

    # 使用**解包字典
    # 示例1:传递可变数量的关键字参数
    def print_info(**kwargs):for key, value in kwargs.items():print(key, ":", value)name = kwargs.get("name", "")age = kwargs.get("age", 0)print(f"{name}{age}岁")print_info(name="李天明", age=20, city="九江")
    # 输出:
    # name : 李天明
    # age : 20
    # city : 九江
    # 李天明有20岁# 示例:拼接字典
    defaults = {"color": "red", "size": "medium"}
    user_preferences = {"size": "large", "theme": "dark"}
    result = {**defaults, **user_preferences}
    print(result)
    # 输出:{'color': 'red', 'size': 'large', 'theme': 'dark'}
    
传递实参
  1. 列表,列表作为函数的实际参数

    def multiply(a, b, c):return a * b * cnumbers = [2, 3, 4]
    result = multiply(*numbers)
    print("====计算结果:",result)  # 输出:24
    
  2. 字典作为函数的实际参数

    def print_info(name, age, city):print(f"{name}来自{city},今年{age}岁")print_info("张三", 20, "北京") #普通调用
    print_info(age=20, name="王五", city="上海")
    user_info={"name":"李四", "city":"九江","age":22,}
    print_info(**user_info) #字典解包
    

http://www.mrgr.cn/news/60152.html

相关文章:

  • 使用docker部署mysql
  • 【NodeJS】NodeJS+mongoDB在线版开发简单RestfulAPI (七):MongoDB的设置
  • 量子计算突破:下一个科技革命的风口浪尖在哪里?
  • Visual Studio2022 Profile 工具使用
  • TCPL-Telecommunications Policy
  • Elasticsearch的实战应用
  • 面向应用型人才的中药炮制教学实训方案
  • 掌握 Golang 性能调优:深入理解 `runtime/debug` 包
  • 分布式储能监控系统在某5MW分布式储能项目中的应用
  • 【源码+文档】基于SpringBoot+Vue健康饮食智慧销售系统【提供源码+答辩PPT+参考文档+项目部署】
  • 自动驾驶---理想汽车智驾进展
  • Django入门教程——动态表格分页展示数据
  • Java版本的基于计算机视觉的跃动小子保卫主公自动通关计划之整体思路篇
  • 创建和管理IPAM
  • Kubernetes:(二)K8Sv1.20二进制部署
  • Lesson12---queue
  • 字节跳动在欧洲设立AI研发中心
  • 如何将 Excel 数据转换为 SQL 脚本:基于 Java 的全面解析
  • MySQL Workbench安装教程(Windows)
  • R语言生物群落(生态)数据统计分析与绘图
  • JAVA基础:IO流 (学习笔记)
  • 【题解】—— LeetCode一周小结43
  • 关于我的数据库——MySQL——第五篇
  • 【隐私计算篇】全同态加密应用场景案例(隐私云计算中的大模型推理、生物识别等)
  • 详细分析Pytorch中的permute基本知识(附Demo)
  • 一文读懂高考志愿专业名词,让你的志愿填报不再迷茫