• 【Django | 开发】面试招聘信息网站(增加csv,excel导出&日志管理功能)


    在这里插入图片描述

    该文章收录专栏
    Django从(图文并茂轻松上手教程)专栏 ✨!!

    🎏内容:
    《Django第二章之增删改查》
    《Django第一章之项目搭建》
    【Django | allauth】登录_注册_邮箱验证_密码邮箱重置
    【Django | allauth】useprofile 用户模型扩展
    【Django | 开发】面试招聘信息网站(快速搭建核心需求)

    一、实现excel表格导入数据(命令行工具)

    • HR需要人肉输入应聘者数据,非常枯燥和耗时,所以我们进行产品的第二次迭代 – 实现候选人数据的导入

    在应用interview创建managment文件以及该目录下command文件,创建import_candidate.py进行脚本操作、

    需要存入的数据
    在这里插入图片描述

    • import_candidates.py (这里选择使用pandas读取数据)
    import pandas as pd
    from django.core.management import BaseCommand
    
    from interview.models import Candidate
    
    
    # python manage.py import_candidates --path file.csv
    class Command(BaseCommand):
        help = '从一个csv导入数据,并存贮到数据库'
    
        # 添加一个长命令 Linux中 -- 表示长命令
        def add_arguments(self, parser):
            parser.add_argument('--path', type=str)  # 所接受参数为一个字符串
    
        # 处理逻辑
        def handle(self, *args, **options):
            path = options['path']  # 从命令行参数读取 path 存贮的路径
            # with open(path, 'r', encoding='gbk') as f:
            #     reader = csv.reader(f, dialect='excel')
            #     for row in reader:
            #         print(row[0])
            candidate_data = pd.read_csv(path, encoding='gbk', )
            for row in range(len(candidate_data)):
                data = list(candidate_data.iloc[row, :])
                print()
                # 创建对象不能Candidate()这是一个类实例,需要通过objects 对象来与数据库交互
                candidate = Candidate.objects.create(
                    user_name=data[0],
                    city=data[1],
                    phone=data[2],
                    bachelor_school=data[3],
                    major=data[4],
                    degree=data[5],
                    test_score_of_general_ability=data[6],
                    page_score=data[7]
                )
                candidate.save()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 命令行输入
    python manage.py import_candidates --path ~/应聘者数据.csv
    
    • 1

    在这里插入图片描述
    在这里插入图片描述

    此时HR非常开心,不用一个一个录入候选人,我们的第二轮开发实现,接下来我们实现 列表查询和筛选

    二、列表查询和筛选&页面再优化

    希望能通过快速筛选得到数据,要求如下
    在这里插入图片描述

    Django官方文档 关于AdminModel 的选项
    强烈建议看官方文档,比任何教程都要强

    • admin.py 文件
    from django.contrib import admin
    
    from interview.models import Candidate
    
    
    # Register your models here.
    
    @admin.register(Candidate)
    class CandidateAdmin(admin.ModelAdmin):
        list_display = ('user_id', 'user_name', 'first_result', 'second_result', 'hr_result', 'create_time', 'modify_time')
    
        # 定义集合的字段列表
        fieldsets = (
            # 第一个元素表示分组展现的名字,第二元素是一个map
    
            (None, {'fields': ("user_id", ("user_name", "email", "gender", "phone",),
                               ("apply_position", "degree"),
                               ("city", "born_address"),
                               ("doctor_school", "bachelor_school", "master_school", "major",), ("page_score",
                                                                                                 "test_score_of_general_ability",
                                                                                                 "candidate_remark",),
                               ), }),
            ('第一轮面试', {'fields': ("first_score", "first_result", "second_interviewer",
                                  ), 'classes': ('collapse',), "description": '请由面试官输入该信息'}),
            ('第二轮面试', {'fields': ("second_score", "second_result", "first_interviewer",
                                  ), 'classes': ('collapse',), "description": '请由面试官输入该信息'}),
            ('第三轮面试', {'fields': ("hr_score", "hr_result", "hr_interviewer",
                                  ), 'classes': ('collapse',), "description": '请由面试官输入该信息'})
        )
    
        list_editable = ('user_id',)  # 可直接在页面修改的数据
        list_display_links = ('user_name',)  # 默认为第一个columns 不想要设置为None 超链接跳转到form表单
        list_per_page = 10  # 每个页面显示多少条数据
        # list_max_show_all = 5 每个页面点击show_all最多显示数据
        list_filter = ('first_result', 'second_result', 'hr_result')  # 按照成绩筛选名字
        # list_select_related = ('user_name', 'first_result')
        # readonly_fields = ( 'modify_time',) # in_list_page non-editable and readonly
        # save_as = True  # 将 save_and_add_another  replace to save_as
        search_fields = ('user_name', 'first_result', 'second_result', 'hr_result',)  # 设置可搜索内容
        ordering = ('hr_result', 'second_result','first_result' ,)  # 默认按照成绩排序好
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 效果:
      在这里插入图片描述

    三、企业域账号集成

    目的:省去多余的账号管理(每个人都要注册一个账号,过于麻烦)

    在这里插入图片描述

    • LDAP 成员页面
      在这里插入图片描述
    • 在服务器的服务
      在这里插入图片描述
      在这里插入图片描述

    1) 安装应用

    pip install django-python3-ldap 
    
    • 1

    在这里插入图片描述

    • setting.py应用将app加进来
      在这里插入图片描述
    • OpenLDAP设置
      在这里插入图片描述在这里插入图片描述

    这样用户可以有两个账号,一个是使用LDAP账号,一个是admin账号,每个员工登陆一下时会需要在每次登录自动录入账号到user群,但却由于显示非员工无法登录,需要在admin后台修改其为员工然后登录,但是这样需要一个一个登录,效率低下

    • 解决:通过manage脚本导入用户信息

    python manage.py ldap_sync_users
    在这里插入图片描述

    2) 设置面试官和HR权限(群组)

    在这里插入图片描述

    • HR的管理页面
      在这里插入图片描述

    四、添加导出为csv功能

    在这里插入图片描述

    • 添加action,指向不同函数进行处理

    操作函数

    import csv
    from datetime import datetime
    # 注册为 action
    @admin.action(description='导出为csv文件')
    def export_model_as_csv(modeladmin, request, queryset):
        # 告诉浏览器以附件处理
        response = HttpResponse(content_type="text/csv")
        field_list = ['user_name', 'first_result', "first_interviewer", 'second_result', "second_interviewer",
                      'hr_result', "hr_interviewer", 'modify_time']
        # attachment 类型是附件 名字为 ""(为字符串,需要单双引号)
        response['Content-Disposition'] = 'attachment; filename= "recruitment_candidate_list_%s.csv"' % (
            datetime.now().strftime('%Y-%m-%d,%H-%M-%S')
        )
        # candidate_list = pd.DataFrame(columns=columns)
        # _meta 是一个Options对象 有get_filed and get_fields 两个方法,得到对象关键字的大写
        writer = csv.writer(response)
        writer.writerow([queryset.model._meta.get_field(f).verbose_name.title() for f in field_list])
        # columns_name = [queryset.model._meta.get_field(f).verbose_name.title() for f in columns]
    
        for obj in queryset:
            ## 单行记录
            csv_line_values = []
            for field in field_list:
                field_object = queryset.model._meta.get_field(field)
                field_values = field_object.value_from_object(obj)
                csv_line_values.append(field_values)
            writer.writerow(csv_line_values)
    
        return response
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    adminmodel类中引入action

    @admin.register(Candidate)
    class CandidateAdmin(admin.ModelAdmin):
        list_display = (
            'user_id', 'user_name', 'first_result', "first_interviewer", 'second_result', "second_interviewer", 'hr_result',
            "hr_interviewer", 'modify_time')
    
        # import actions to use
        actions = [export_model_as_csv, ]
     
     ···
      
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 效果
      在这里插入图片描述

    六、添加excel导出功能(样式)

    此时HR需要能够导出一个具有好看样式的表格,可以统计S分数的候选人,此时我们使用python中处理excel表格文件的三板斧 xlrd - xlwt - xlutils

    • 在需要导入excel文件,我们可以用xlrd-xlutils-xlwt,通过xlutilsbook转换为workbook ,进行读写操作

    这里现在只需要用到xlrt

    
    def setStyle(name, height=200, font_color=256, background_color=0x40, background=False, bold=False, align=True,
                 border=False, border_size=1):
    	"""
    	xlwt样式写入设置
    	"""
    	style = xlwt.XFStyle()  # 初始化样式
    	if background:
    		# 创建背景模式对像
    		pattern = xlwt.Pattern()
    		# 固定样式
    		pattern.pattern = xlwt.Pattern.SOLID_PATTERN  # May be: NO_PATTERN, SOLID_PATTERN, or 0x00 through 0x12
    		pattern.pattern_fore_colour = background_color  # 设置模式颜色 May be: 8 through 63. 0 = Black, 1 = White, 2 = Red, 3 = Green, 4 = Blue, 5 = Yellow, 6 = Magenta, 7 = Cyan, 16 =
    		# Maroon, 17 = Dark Green, 18 = Dark Blue, 19 = Dark Yellow , almost brown), 20 = Dark Magenta, 21 = Teal, 22 = Light Gray, 23 = Dark Gray, the list goes on...
    		style.pattern = pattern
    	font = xlwt.Font()  # 为样式创建字体
    	# 字体类型:比如宋体、仿宋也可以是汉仪瘦金书繁
    	font.name = name
    	# 设置字体颜色
    	font.colour_index = font_color
    	# 字体大小
    	font.height = height
    	# 字体加粗
    	font.bold = bold
    	# 定义格式
    	style.font = font
    
    	if border:
    		# 框线
    		borders = xlwt.Borders()
    		borders.left = border_size
    		borders.right = border_size
    		borders.top = border_size
    		borders.bottom = border_size
    		style.borders = borders
    	# 细实线:1,小粗实线:2,细虚线:3,中细虚线:4,大粗实线:5,双线:6,细点虚线:7
    	# 大粗虚线:8,细点划线:9,粗点划线:10,细双点划线:11,粗双点划线:12,斜点划线:13
    	if align:
    		# 设置单元格对齐方式
    		al = xlwt.Alignment()
    		# 0x01(左端对齐)、0x02(水平方向上居中对齐)、0x03(右端对齐)
    		al.horz = 0x02
    		# 0x00(上端对齐)、 0x01(垂直方向上居中对齐)、0x02(底端对齐)
    		al.vert = 0x01
    		style.alignment = al
    
    	return style
    
    
    # 注册为 action
    @admin.action(description='导出为excel文件')
    def export_model_as_excel(modeladmin, request, queryset):
    	# 告诉浏览器以附件处理
    	response = HttpResponse(content_type='application/vnd.ms-excel')
    	field_list = ['user_name', 'first_result', "first_interviewer", 'second_result', "second_interviewer",
    	              'hr_result', "hr_interviewer", "modify_time"]
    	# attachment 类型是附件 名字为 ""(为字符串,需要单双引号)
    	response['Content-Disposition'] = 'attachment; filename= "recruitment_candidate_list_%s.xlsx"' % (
    		datetime.now().strftime('%Y-%m-%d,%H-%M-%S')
    	)
    	# 使用 xlwt 生成表格
    	title = ['应聘候选人信息']
    	wb = xlwt.Workbook(encoding='utf-8')  # 创建一个excel  #ascii'可视为'utf-8'的一部分,so用'utf-8'更好
    	ws = wb.add_sheet('候选人')  # 新建一个工作表
    	ws.write_merge(0, 1, 0, len(field_list) - 1, title, style=setStyle('微软雅黑', height=200, font_color=256,  bold=True, border=True, border_size=1))
    	for col, name in enumerate(field_list):  # 变为枚举类型,默认从0开始,
    		ws.write(2, col, queryset.model._meta.get_field(name).verbose_name.title(), style=setStyle('微软雅黑', height=200, font_color=0x40, background=True, background_color=0x4682B4))
    	row = 3  # 从第三行开始
    	# style_date = xlwt.XFStyle()
    	# style_date.num_format_str = 'M/D/YY h:mm'
    	S_sum = 0
    	for obj in queryset:
    		columns = 0
    		# # 单行记录
    		for field in field_list:
    			field_object = queryset.model._meta.get_field(field)
    			field_values = field_object.value_from_object(obj)
    			logger.warning(type(field_values))
    			if type(field_values) == type(datetime.today()):  # 判断是否为datetime数据类型,并指定数据为时间格式
    				field_values = field_values.strftime('%Y/%m/%d,%H:%M:%S')
    				ws.write(row, columns, field_values)
    			else:
    				# 累加S级别人数
    				if field_values == 'S':
    					S_sum += 1
    				ws.write(row, columns, field_values)
    			columns += 1
    		# 时间行宽增大
    		row += 1
    	ws.col(columns - 1).width = 5000
    	ws.col(columns - 2).width = 5000
    	ws.write(row + 2, len(field_list) - 2, '终面S级别人数:', setStyle(name='仿宋', bold=True))
    	ws.write(row + 2, len(field_list) - 1, S_sum)
    
    	logger.warning('{} exported {} candidate records'.format(request.user, len(queryset)))
    	wb.save(response)  # 保存到文件类对象
    
    	return response
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 导出样式

    在这里插入图片描述

    五、记录日志以方便排查问题

    1) 项目配置

    • 记录详细的日志信息可以快速排查问题
      在这里插入图片描述

    python格式一样,使用 dictConfig格式来定义日志信息,在处理级别时是按照过滤原则handler处理其级别信息上传到记录器 记录器再根据自身级别过滤上传root再过滤

    在项目的setting.py文件中进行如下配置

    
    # log record
    LOGGING = {
    	'version': 1,  # 必须
    	"disable_existing_loggers": False,  # 设置其他日志同时记录
    	'handlers': {
    		'console': {  # handler 名称(表示控制台输出)
    			"class": "logging.StreamHandler",  # 在控制台流 类
    			'formatter': 'simple',
    			'level': 'INFO'
    		},
    		'file': {  # handler 名称 (表示文件输出)
    			'level': 'INFO',
    			'class': 'logging.FileHandler',  # 文件流类
    			'formatter': 'simple',
    			# 得到完整路径并拼接
    			'filename': os.path.join(BASE_DIR, 'logs/debug.log'),
    		},
    	},
    	'formatters': {
    		# simple 类
    		'simple': {
    			'format': '%(asctime)s , %(name)s [ %(levelname)s ] %(message)s',
    		}
    	},
    
    	# 根日志记录器(父记录器)
    	'root': {
    		'handlers': ['console', 'file'],  # 记录到文件和控制台中
    		'level': 'INFO',
    	},
    	'loggers': {
    		'django': {
    			'handlers': ['file'],
    			'level': 'DEBUG',
    			'propagate': True,
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 运行服务器查看
    python manage.py runserver 0.0.0.0:8000
    
    • 1

    在这里插入图片描述

    2)在admin中配置python的logging模块

    # 得到 当前日志记录对象
    # logging.basicConfig(level=logging.DEBUG,format="'%(asctime) %(name) %(levelname) %(message)")
    logger = logging.getLogger(__name__)
    
    	def ·······
    			·······
        # 输出 导出对象以及条数(只有warning以上才会被打印,可以自己配置)
        logger.warning('{} exported {} candidate records'.format(request.user, len(queryset)))
    
        return response
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在这里插入图片描述
    在这里插入图片描述

    参考文献:
    Python 常用模块大全(整理)
    python的xlwt模块使用

    			        🤞到这里,如果还有什么疑问🤞
    		🎩欢迎私信博主问题哦,博主会尽自己能力为你解答疑惑的!🎩
    			🥳如果对你有帮助,你的赞是对博主最大的支持!!🥳
    
    • 1
    • 2
    • 3
  • 相关阅读:
    ISP代理是什么?双ISP是什么意思?
    python+django校园社交高校交友网站2x7r5.
    OJ题目【栈和队列】
    Opecv检测多个圆形(霍夫圆检测,轮廓面积筛选,C/C++)
    PowerManagerService启动-Android12
    vue2修改组件样式
    通过vNode实现给列表字段打标签
    Java.lang.Class类 getGenericInterfaces()方法有什么功能呢?
    HTML5期末考核大作业,网站——青岛民俗 7页。 美丽家乡 学生旅行 游玩 主题住宿网页
    【Pytorch基础教程32】spark或dl模型部署(MLFlow/ONNX/Runtime/tensorflow serving)
  • 原文地址:https://blog.csdn.net/weixin_66526635/article/details/125682342