〔十四〕员工信息模型:60个字段的设计思路与验证器

📅 2026/7/15 6:34:17 👁️ 阅读次数 📝 编程学习
〔十四〕员工信息模型:60个字段的设计思路与验证器

📢 阅读提示

感谢你阅读本章。本文所有代码和注释均来自真实项目,为了能让更多认真学习的读者持续获得优质内容,本文将在7天后转为“粉丝可见”。
如果你觉得本文有价值,欢迎收藏并关注我,本系列博客将继续保持同样详细的注释风格。
感谢理解与支持!


一、业务场景

在第5-13章,我们完成了组织机构模块(部门、用户资料、权限)。现在需要管理企业全体员工的档案信息,包括:

  • 基础信息(员工编码、姓名、身份证、头像)
  • 个人基本信息(性别、民族、出生日期、婚姻状况、联系电话等)
  • 教育背景(毕业院校、专业、学历)
  • 工作信息(参工时间、职位、工种、员工状态等)
  • 组织与政治信息(入党时间、政治面貌、岗位层级)
  • 资质信息(资格级别、资格名称)
  • 特殊标记(违法犯罪记录、特殊人员、退役军人、军人家属)—— 跨模块联动的关键开关
  • 审计与软删除字段

这些字段总数超过60个,并且有大量 Choice 枚举(民族、政治面貌、学历、员工状态等)。模型设计要兼顾录入效率(Admin 字段分组)、数据质量(验证器)、查询性能(冗余显示字段、索引)。

与组织机构模块的区别

  • 组织机构模型(DepartmentUserProfile)字段较少,且UserProfile仅针对系统管理者。
  • 员工模型是全量人事档案,字段多、枚举细、验证规则复杂,是企业管理的核心数据源。

二、模型字段分类总览

下面按业务逻辑将60+字段分为8大类,方便理解。

分类字段列表说明
基础信息employee_number,full_name,id_number,avatar唯一编码、姓名、身份证、头像
个人基本信息gender,gender_display,nation,nation_display,birth_date,native_place,marital_status,marital_status_display,phone,permanent_address含冗余显示字段
教育背景graduation_school,first_major,graduation_date,first_education,first_education_display第一学历、毕业信息
工作信息join_work_date,position,job_type,actual_unit,employee_status,employee_status_display,employee_group,employee_subgroup含员工状态(细粒度)
组织与政治信息join_organization_date,political_status,political_status_display,position_level,position_level_display,personal_identity,personal_identity_display政治面貌、岗位层级、个人身份
资质信息qualification_level,qualification_level_display,qualification_name,qualification_name_display职称/资格
特殊标记has_criminal_record,is_special_personnel,is_veteran,is_military_family跨模块联动开关
审计+软删除created_at,updated_at,created_by,updated_by,is_deleted,deleted_at,deleted_by,delete_reason与第6章相同,复用设计

三、特殊标记字段:跨模块联动的数据开关(核心亮点)

这四个布尔字段不是简单的“是/否”记录,而是整个系统的行为开关。它们控制着其他业务模块的数据显示、录入权限和业务规则。

字段业务含义在后续模块中的用途
has_criminal_record有无违法犯罪记录违法违纪管理:只有标记为“有”的员工,才能在案件模块中被关联。在案件记录的“关联员工”下拉框中,自动过滤掉has_criminal_record=False的员工,从源头防止错误关联。
is_special_personnel是否特殊人员(如重点稳控对象)安保防恐排查:在重点部位、工单任务中,系统自动高亮标记特殊人员,提醒保卫人员重点监控。
is_veteran是否退役军人先进个人申报:在评优评先时,系统可自动统计退役军人占比;工单任务:可优先分配给退役军人党员等。
is_military_family是否军人家属节假日慰问:系统可筛选出军人家属,生成慰问名单;帮扶救助:优先考虑军属家庭。

设计理念:数据源头控制,一次标记,多处联动。
例如,当一名员工在员工信息表中勾选has_criminal_record = True后:

  1. 在违法违纪模块的“关联员工”下拉框中,该员工会自动出现(而其他员工不出现)。
  2. 选择该员工后,系统自动从员工表读取姓名、部门、身份证等信息,填充到案件的快照字段中(避免重复录入)。
  3. 在案件统计报表中,该员工会被计入违法犯罪人员统计。

代码示例(第7章已实现,此处仅展示调用方式)

# illegalcase/admin.py 中的 formfield_for_foreignkeydefformfield_for_foreignkey(self,db_field,request,**kwargs):ifdb_field.name=="employee":# 只显示 has_criminal_record=True 的员工qs=EmployeeBasicInfo.objects.filter(has_criminal_record=True,department_id__in=viewable_dept_ids,is_deleted=False)# ... 其他配置

如果没有这些特殊标记字段,违法违纪模块就无法自动筛选符合条件的人员,需要人工去核对,既低效又容易出错。

这就是为什么员工基础信息是后续所有业务模块的“数据基石”——没有准确的员工标记,后续的案件管理、安保排查、工单流转等都无从谈起。

四、冗余显示字段的设计(性能优化亮点)

在员工模型中,很多字段是 ChoiceField(如性别、民族、员工状态)。数据库存储的是代码(如 ‘在册在岗’),但在 Admin 列表页我们希望直接显示中文,而不是每次都调用 get_xxx_display()(会产生额外查询)。

解决方案:增加冗余字段(xxx_display),在 save() 中自动从 Choice 代码填充显示值。查询时直接读取该字段,无需调用方法。

# models.py(简化示例)gender=models.CharField(max_length=10,choices=GENDER_CHOICES,null=True,blank=True)gender_display=models.CharField(max_length=10,blank=True,null=True,help_text='自动从性别字段填充')

在 save() 中调用 _fill_display_fields() 方法(见第七节)。

五、字段验证器(模型层统一验证)

验证器写在字段的 validators 参数中,确保无论通过 Admin、导入、API 保存数据,都会执行验证。

5.1 手机号验证器 validate_phone

defvalidate_phone(value):ifvalue:# 支持手机号(含+86)、座机(区号-号码)、纯数字7-8位pattern=r'^(\+?86)?1[3-9]\d{9}$|^0\d{2,3}-?\d{7,8}$|^\d{7,8}$'ifnotre.match(pattern,value.replace(' ','')):raiseValidationError('请输入有效的联系电话格式(手机号或座机)')

5.2 身份证基本格式验证 validate_id_number

defvalidate_id_number(value):ifnotvalue:return# 15位或18位,最后一位可为Xifnotre.match(r'^(\d{15}|\d{17}[\dXx])$',value):raiseValidationError('身份证号码格式不正确(15位或18位)')

注意:内部项目无法接入公安接口,只做基本格式校验。

5.3 头像大小验证 validate_image_size

defvalidate_image_size(value):limit=2*1024*1024# 2MBifvalueandvalue.size>limit:raiseValidationError('图片大小不能超过2MB')

5.4 头像上传路径 employee_avatar_path

defemployee_avatar_path(instance,filename):# 防止路径遍历攻击:替换 / 和 \safe_number=str(instance.employee_number).replace('/','_').replace('\\','_')ext=filename.split('.')[-1]if'.'infilenameelse'jpg'returnf'employee_avatars/{safe_number}.{ext}'

六、Choice 枚举定义(部分)

模型中定义了十几个 Choice 元组,例如:

POLITICAL_CHOICES=[('中共党员','中共党员'),('预备中共党员','预备中共党员'),('共青团员','共青团员'),('群众','群众'),('民主党派','民主党派'),# ...]STATUS_CHOICES=[('在册在岗','在册在岗'),('在册不在岗','在册不在岗'),('在册不在岗-其他','在册不在岗-其他'),('退休','退休'),('调出','调出'),# ...]

这些枚举贴近国企真实业务,体现了数据的精细度。

七、save() 方法重写

defsave(self,*args,**kwargs):# 1. 自动填充冗余显示字段self._fill_display_fields()# 2. 同步部门快照(如果有关联部门)ifself.department:self.department_name=self.department.nameelse:self.department_name=''super().save(*args,**kwargs)

_fill_display_fields() 内部使用 get_xxx_display() 方法填充显示字段(仅当为空时填充,避免覆盖用户手动修改)。

八、软删除与审计字段(复用第6章)

员工模型直接继承了与 Department 相同的软删除和审计字段设计,包括:

· is_deleted, deleted_at, deleted_by, delete_reason
· created_at, updated_at, created_by, updated_by

具体原理见第6章,本章不再重复。

九、元数据与索引

classMeta:verbose_name='员工基础信息'verbose_name_plural='员工基础信息'ordering=['employee_number']indexes=[models.Index(fields=['department','is_deleted']),models.Index(fields=['is_archived','is_deleted']),]

为常用联合查询字段添加索引,提升列表页性能。

十、注意事项(踩坑经验)

序号注意事项踩坑总结
1冗余显示字段只填充一次_fill_display_fields 中判断 if not self.gender_display 再赋值,避免每次保存都覆盖用户可能手动修正的值
2头像路径安全使用 replace 过滤路径分隔符,防止恶意上传 …/…/config.py 导致文件覆盖
3身份证验证不严格内部系统够用,若需更强校验可接入第三方 API
4员工状态枚举值很长如“在册不在岗-其他长期休假人员(六个月以上)”,在 Admin 下拉框中会折行,不影响功能
5null=True 与 blank=True大多数业务字段允许空(blank=True),因为历史数据可能不完整
6与组织机构模块的区分UserProfile 是系统使用者(管理员),EmployeeBasicInfo 是全体员工。两者通过 employee_id 或 employee_number 可关联但非强制
7特殊标记字段的初始值默认均为 False,需要由保卫干事根据实际情况勾选。一旦标记,后续模块立即生效

十一、小结

本章完成了员工信息模型的全解析:

· 60+ 字段按业务分类
· 四个特殊标记字段的跨模块联动价值(重点)
· 冗余显示字段的性能优化
· 三大字段验证器(手机号、身份证、头像)
· Choice 枚举的组织
· save() 重写自动填充
· 复用第6章的软删除/审计

至此,员工信息的数据结构已就绪,并且明确了它在整个系统中的“数据基石”地位。 下一章我们将进入 员工数据导入,包括模板生成、三步验证、逐行事务处理,以及“导出→修改→导入”的完美闭环。


互动问题:你的业务系统中,有哪些类似的“标记字段”用来控制其他模块的行为?欢迎评论区分享你的设计思路。