当前位置:   article > 正文

Django后台项目开发实战五

Django后台项目开发实战五

完成两个功能:

  1. HR 可以维护候选人信息
  2. 面试官可以录入面试反馈

第五阶段

创建 interview 应用,实现候选人面试评估表的增删改功能,并且按照页面分组来展示不同的内容,如候选人基础信息,一面,二面的面试结果,HR 的面试结果

我们可以使用 pycharm 上面菜单栏中 Tools 里的 Run manage.py task,这样就不用每次都输入前面的命令了

输入命令 startapp interview

创建完应用后,打开 models.py 文件,开始编写数据建模代码

  1. from django.db import models
  2. # 第一论面试结果
  3. FIRST_INTERVIEW_RESULT_TYPE = (('建议复试','建议复试'),('待定','待定'),('放弃','放弃'))
  4. # 复试面试建议
  5. INTERVIEW_RESULT_TYPE = (('建议录用','建议录用'),('待定','待定'),('放弃','放弃'))
  6. # 候选人学历
  7. DEGREE_TYPE = (('本科','本科'),('硕士','硕士'),('博士','博士'))
  8. # HR终面结论
  9. HR_SCORE_TYPE = (('S','S'),('A','A'),('B','B'),('C','C'))
  10. class Candidate(models.Model):
  11. # 基础信息
  12. userid = models.IntegerField(unique=True, blank=True, null=True, verbose_name='应聘者ID')
  13. username = models.CharField(max_length=135, verbose_name='姓名')
  14. city = models.CharField(max_length=135, verbose_name='城市')
  15. phone = models.CharField(max_length=135, verbose_name='手机号码')
  16. email = models.EmailField(max_length=135, blank=True, verbose_name='邮箱')
  17. apply_position = models.CharField(max_length=135, blank=True, verbose_name='应聘职位')
  18. born_address = models.CharField(max_length=135, blank=True, verbose_name='生源地')
  19. gender = models.CharField(max_length=135, blank=True, verbose_name='性别')
  20. candidate_remark = models.CharField(max_length=135, blank=True, verbose_name='候选人信息备注')
  21. # 学校与学历信息
  22. bachelor_school = models.CharField(max_length=135, blank=True, verbose_name=' 本科学校')
  23. master_school = models.CharField(max_length=135, blank=True, verbose_name='研究生学校')
  24. doctor_school = models.CharField(max_length=135, blank=True, verbose_name='博士生学校')
  25. major = models.CharField(max_length=135, blank=True, verbose_name='专业')
  26. degree = models.CharField(max_length=135, choices=DEGREE_TYPE, blank=True, verbose_name='学历')
  27. # 综合能力测评成绩,笔试测评成绩
  28. test_score_of_general_ability = models.DecimalField(decimal_places=1,null=True,max_digits=3,blank=True,
  29. verbose_name='综合能力测评成绩')
  30. paper_score = models.DecimalField(decimal_places=1, null=True, max_digits=3, blank=True, verbose_name='笔试成绩')
  31. # 第一轮面试记录
  32. first_score = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True, verbose_name='初始分')
  33. first_learning_ability = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True, verbose_name='学习能力得分')
  34. first_professional_competency = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True, verbose_name='专业能力得分')
  35. first_advantage = models.TextField(max_length=1024, blank=True, verbose_name='优势')
  36. first_disadvantage = models.TextField(max_length=1024, blank=True, verbose_name='顾虑和不足')
  37. first_result = models.CharField(max_length=256, choices=FIRST_INTERVIEW_RESULT_TYPE, blank=True,
  38. verbose_name='初试结果')
  39. first_recommend_position = models.CharField(max_length=256, blank=True, verbose_name='推荐部门')
  40. first_interviewer = models.CharField(max_length=256, blank=True, verbose_name='初试面试官')
  41. first_remark = models.CharField(max_length=135, blank=True, verbose_name='初试备注')
  42. # 第二轮面试记录
  43. second_score = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True, verbose_name='专业复试得分')
  44. second_learning_ability = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
  45. verbose_name='学习能力得分')
  46. second_professional_competency = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
  47. verbose_name='专业能力得分')
  48. second_pursue_of_excellence = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
  49. verbose_name='追求卓越得分')
  50. second_communication_ability = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
  51. verbose_name='沟通能力得分')
  52. second_pressure_score = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
  53. verbose_name='抗压能力得分')
  54. second_advantage = models.TextField(max_length=1024, blank=True, verbose_name='优势')
  55. second_disadvantage = models.TextField(max_length=1024, blank=True, verbose_name='顾虑和不足')
  56. second_result = models.CharField(max_length=256, choices=INTERVIEW_RESULT_TYPE, blank=True,
  57. verbose_name='专业复试结果')
  58. second_recommend_position = models.CharField(max_length=256, blank=True, verbose_name='建议方向或推荐部门')
  59. second_interviewer = models.CharField(max_length=256, blank=True, verbose_name='专业复试面试官')
  60. second_remark = models.CharField(max_length=135, blank=True, verbose_name='专业复试备注')
  61. # HR终面
  62. hr_score = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True,
  63. verbose_name='HR复试综合等级')
  64. hr_responsibility = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True,
  65. verbose_name='HR责任心')
  66. hr_communication_ability = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True,
  67. verbose_name='HR坦诚沟通')
  68. hr_logic_ability = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True,
  69. verbose_name='HR逻辑思维')
  70. hr_potential = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True,
  71. verbose_name='HR发展潜力')
  72. hr_stability = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True,
  73. verbose_name='HR稳定性')
  74. hr_advantage = models.TextField(max_length=1024, blank=True, verbose_name='优势')
  75. hr_disadvantage = models.TextField(max_length=1024, blank=True, verbose_name='顾虑和不足')
  76. hr_result = models.CharField(max_length=256, choices=INTERVIEW_RESULT_TYPE, blank=True,
  77. verbose_name='HR面试结果')
  78. hr_interviewer = models.CharField(max_length=256, blank=True, verbose_name='HR面试官')
  79. hr_remark = models.CharField(max_length=135, blank=True, verbose_name='HR复试备注')
  80. creator = models.CharField(max_length=256, blank=True, verbose_name='候选人数据的创建人')
  81. created_date = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
  82. modified_date = models.DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name="更新时间")
  83. last_editor = models.CharField(max_length=256, blank=True, verbose_name='最后编辑者')
  84. class Meta:
  85. db_table = 'candidate'
  86. verbose_name = '应聘者'
  87. verbose_name_plural = '应聘者'
  88. def __str__(self):
  89. return self.username

然后在 admin.py 文件注册数据模型,并且展示时隐藏一些字段

  1. from django.contrib import admin
  2. from interview.models import Candidate
  3. class CandidateAdmin(admin.ModelAdmin):
  4. exclude = ('creator','created_date','modified_date')
  5. list_display = ('username','city','bachelor_school','first_score','first_result','first_interviewer',
  6. 'second_result','second_interviewer','hr_score','hr_result','last_editor')
  7. admin.site.register(Candidate,CandidateAdmin)

再到 setting.py 文件注册应用

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'jobs',
  9. 'interview'
  10. ]

最后执行数据库迁移,还是那两个命令

  1. makemigrations
  2. migrate

 效果图如下:

大家看到这个页面其实非常长,因为我们的字段实在是太多了,用起来很复杂,所以面试官也好,还是hr也好,他们其实不太清楚哪些内容是他需要填的,所以我们对这个页面进行优化,把这个页面的内容分组展示

为了方便,我们使用 pycharm 的代码编辑器,新建一个文本文档,把 models.py 里面的字段粘贴过来,然后在这个文件里面去做批量编辑。

首先 ctrl r 来做一个正则表达式的替换,输入 =.*$

然后点击星号匹配,再点击 replace all ,替换掉所有,再删除一些多余的字段

然后再输入一个空格,再点击 replace all ,替换掉所有的空格

然后再输入 ^ 和 '' ,再点击 replace all ,替换开头为 "

然后再输入  $ 和 '' ,再点击 replace all ,替换结尾为 "

然后再输入  $ 和 , ,再点击 replace all ,替换结尾为 ,

最后点 edit 这里有个 join line,可以把字段都连起来

再删除一些多余的标点,最后的成果如下

  1. #基础信息,学校与学历信息,综合能力测评成绩,笔试测评成绩,
  2. "userid", "username", "city", "phone", "email", "apply_position", "born_address", "gender", "candidate_remark", "bachelor_school", "master_school", "doctor_school", "major", "degree", "test_score_of_general_ability", "paper_score",
  3. #第一轮面试记录,
  4. "first_score", "first_learning_ability", "first_professional_competency", "first_advantage", "first_disadvantage", "first_result", "first_recommend_position", "first_interviewer", "first_remark",
  5. #第二轮面试记录,
  6. "second_score", "second_learning_ability", "second_professional_competency", "second_pursue_of_excellence", "second_communication_ability", "second_pressure_score", "second_advantage", "second_disadvantage", "second_result", "second_recommend_position", "second_interviewer", "second_remark",
  7. #HR终面,
  8. "hr_score", "hr_responsibility", "hr_communication_ability", "hr_logic_ability", "hr_potential", "hr_stability", "hr_advantage", "hr_disadvantage", "hr_result", "hr_interviewer", "hr_remark",

然后把这些字段添加到 admin.py 文件的函数里,同时在字段之前添加小括号来分小组,让一行可以展示多个数据

  1. class CandidateAdmin(admin.ModelAdmin):
  2. ...
  3. fieldsets = (
  4. (None,{'fields':("userid", ("username", "city"), ("phone", "email"), ("apply_position", "born_address"), ("gender", "candidate_remark"), ("bachelor_school", "master_school", "doctor_school"), ("major", "degree"), ("test_score_of_general_ability", "paper_score"))}),
  5. ('第一轮面试记录', {'fields': (("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage", "first_result", "first_recommend_position", "first_interviewer", "first_remark")}),
  6. ('第二轮专业复试记录', {'fields': (("second_score", "second_learning_ability", "second_professional_competency"), ("second_pursue_of_excellence", "second_communication_ability", "second_pressure_score"), "second_advantage", "second_disadvantage", "second_result", "second_recommend_position", "second_interviewer", "second_remark")}),
  7. ('HR复试记录', {'fields': (("hr_score", "hr_responsibility", "hr_communication_ability"), ("hr_logic_ability", "hr_potential", "hr_stability"), "hr_advantage", "hr_disadvantage", "hr_result", "hr_interviewer", "hr_remark")})
  8. )

刷新界面,发现已经分好组了。这里我就不截图了,太长。

接下来我们再做进一步优化,一般我们都不会自己去输入候选人的基本信息,而是会拿到候选人的 excel 表,或者 csv 文件,那么如何导入候选人 csv 文件呢?

我们在 interview 应用下创建文件夹目录 management/commands ,创建 import_candidates.py 文件,添加如下代码

  1. import csv
  2. from django.core.management import BaseCommand
  3. from interview.models import Candidate
  4. class Command(BaseCommand):
  5. help = "从csv导入候选人基本信息"
  6. def add_arguments(self, parser):
  7. parser.add_argument('--path', type=str)
  8. def handle(self, *args, **options):
  9. path = options['path']
  10. #编码格式选择合适的
  11. with open(path, 'rt',encoding='gbk') as f:
  12. #csv分割符选择合适的,不选默认为','分割
  13. #reader = csv.reader(f,dialect='excel',delimiter=';')
  14. reader = csv.reader(f, dialect='excel')
  15. for row in reader:
  16. candidate = Candidate.objects.create(
  17. username=row[0],
  18. city=row[1],
  19. phone=row[2],
  20. bachelor_school=row[3],
  21. major=row[4],
  22. degree=row[5],
  23. test_score_of_general_ability=row[6],
  24. paper_score=row[7]
  25. )

展示一下 excel 的内容

然后把 excel 文件导出为 csv 格式文件,并删除第一行,如下图

在 pycharm 的 run manage.py task 输入命令

import_candidates --path C:/Users/ASUS/Desktop/candidates.csv

刷新界面,发现导入成功

这个时候系统里面有很多简历了,成百上千的简历里面要查找特定候选人的简历,或者按照状态来查询待面试,或者已经面试通过的候选人查找的效率比较低,希望能够快速查询跟筛选,接下来我们实现下面的两个功能。

第一个能够按照名字、手机号码学校来查询候选人

第二个能够按照初试的结果,HR 复试的结果面试官来筛选,然后也能够按照复试结果来排序,复试通过的优先排在前面

修改 admin.py 文件为下面的代码

  1. from django.contrib import admin
  2. from interview.models import Candidate
  3. from datetime import datetime
  4. class CandidateAdmin(admin.ModelAdmin):
  5. exclude = ('creator','created_date','modified_date')
  6. list_display = ('username','city','bachelor_school','first_score','first_result','first_interviewer',
  7. 'second_result','second_interviewer','hr_score','hr_result','last_editor')
  8. # 筛选条件
  9. list_filter = ('city','first_result','second_result','hr_result',
  10. 'first_interviewer','second_interviewer','hr_interviewer')
  11. # 查询字段
  12. search_fields = ('username','phone','email','bachelor_school')
  13. # 自动排序字段
  14. ordering = ('hr_result','second_result','first_result')
  15. # 分组展示字段
  16. fieldsets = (
  17. (None,{'fields':("userid", ("username", "city"), ("phone", "email"), ("apply_position", "born_address"), ("gender", "candidate_remark"), ("bachelor_school", "master_school", "doctor_school"), ("major", "degree"), ("test_score_of_general_ability", "paper_score"))}),
  18. ('第一轮面试记录', {'fields': (("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage", "first_result", "first_recommend_position", "first_interviewer", "first_remark")}),
  19. ('第二轮专业复试记录', {'fields': (("second_score", "second_learning_ability", "second_professional_competency"), ("second_pursue_of_excellence", "second_communication_ability", "second_pressure_score"), "second_advantage", "second_disadvantage", "second_result", "second_recommend_position", "second_interviewer", "second_remark")}),
  20. ('HR复试记录', {'fields': (("hr_score", "hr_responsibility", "hr_communication_ability"), ("hr_logic_ability", "hr_potential", "hr_stability"), "hr_advantage", "hr_disadvantage", "hr_result", "hr_interviewer", "hr_remark")})
  21. )
  22. def save_model(self, request, obj, form, change):
  23. obj.last_editor = request.user.username
  24. if not obj.creator:
  25. obj.creator = request.user.username
  26. obj.modified_date = datetime.now()
  27. obj.save()
  28. admin.site.register(Candidate,CandidateAdmin)

效果图:

现在我们再加一个功能,将数据导出为 csv 文件,修改 admin.py 文件如下

  1. from django.contrib import admin
  2. from interview.models import Candidate
  3. from datetime import datetime
  4. from django.http import HttpResponse
  5. import csv
  6. exportable_fields = ('username','city',"phone",'bachelor_school','degree','first_result','first_interviewer',
  7. 'second_result','second_interviewer','hr_score','hr_result')
  8. def export_model_as_csv(modeladmin,request,queryset):
  9. response = HttpResponse(content_type='text/csv')
  10. field_list = exportable_fields
  11. #可以使用 request 中的 User-Agent 进行客户端系统判断,如果用户的系统是 Windows,那么给导出的文件编码设置为带有 BOM 的 UTF-8,否则使用 UTF-8
  12. response.charset = 'utf-8-sig' if "Windows" in request.headers.get('User-Agent') else 'utf-8'
  13. #Content-Disposition 响应标头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地
  14. response['Context-Disposition'] = 'attachment;filename="recruitment-candidates-list-%s.csv"' %(
  15. datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
  16. )
  17. # 写入表头
  18. print(response['Context-Disposition'])
  19. writer = csv.writer(response)
  20. writer.writerow(
  21. [queryset.model._meta.get_field(f).verbose_name.title() for f in field_list]
  22. )
  23. for obj in queryset:
  24. # 单行的记录(各个字段的值),写入csv文件
  25. csv_line_values = []
  26. for field in field_list:
  27. field_object = queryset.model._meta.get_field(field)
  28. field_value = field_object.value_from_object(obj)
  29. csv_line_values.append(field_value)
  30. writer.writerow(csv_line_values)
  31. return response
  32. #国际化文本
  33. export_model_as_csv.short_description = '导出为CSV文件'
  34. class CandidateAdmin(admin.ModelAdmin):
  35. actions = [export_model_as_csv]
  36. exclude = ('creator','created_date','modified_date')
  37. list_display = ('username','city','bachelor_school','first_score','first_result','first_interviewer',
  38. 'second_result','second_interviewer','hr_score','hr_result','last_editor')
  39. # 筛选条件
  40. list_filter = ('city','first_result','second_result','hr_result',
  41. 'first_interviewer','second_interviewer','hr_interviewer')
  42. # 查询字段
  43. search_fields = ('username','phone','email','bachelor_school')
  44. # 自动排序字段
  45. ordering = ('hr_result','second_result','first_result')
  46. # 分组展示字段
  47. fieldsets = (
  48. (None,{'fields':("userid", ("username", "city"), ("phone", "email"), ("apply_position", "born_address"), ("gender", "candidate_remark"), ("bachelor_school", "master_school", "doctor_school"), ("major", "degree"), ("test_score_of_general_ability", "paper_score"))}),
  49. ('第一轮面试记录', {'fields': (("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage", "first_result", "first_recommend_position", "first_interviewer", "first_remark")}),
  50. ('第二轮专业复试记录', {'fields': (("second_score", "second_learning_ability", "second_professional_competency"), ("second_pursue_of_excellence", "second_communication_ability", "second_pressure_score"), "second_advantage", "second_disadvantage", "second_result", "second_recommend_position", "second_interviewer", "second_remark")}),
  51. ('HR复试记录', {'fields': (("hr_score", "hr_responsibility", "hr_communication_ability"), ("hr_logic_ability", "hr_potential", "hr_stability"), "hr_advantage", "hr_disadvantage", "hr_result", "hr_interviewer", "hr_remark")})
  52. )
  53. def save_model(self, request, obj, form, change):
  54. obj.last_editor = request.user.username
  55. if not obj.creator:
  56. obj.creator = request.user.username
  57. obj.modified_date = datetime.now()
  58. obj.save()
  59. admin.site.register(Candidate,CandidateAdmin)

效果图:

点击执行成功下载,打开文件效果如下

目前这个导出 csv 文件的文件名会显示乱码,并不能输出我们期望的文件名,暂时我并没有找到解决方法,如果有写出来的大佬,务必私信我,感谢!!!

第五阶段结束啦!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/518029
推荐阅读
相关标签
  

闽ICP备14008679号