第六阶段
日志记录
日志处理教程 Django 日志处理
我这里实现一个简单的日志,在 setting.py 文件添加日志
LOGGING = {
# 版本
'version': 1,
# 是否禁止默认配置的记录器
'disable_existing_loggers': False,
'formatters': {
'simple': {
'format': '%(asctime)s %(name)-12s %(lineno)d %(levelname)-8s %(message)s'
}
},
'handlers': {
# 标准输出
'console': {
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'mail_admins':{
'level': 'ERROR',
'class':'django.utils.log.AdminEmailHandler'
},
# 自定义 handlers,输出到文件
'file': {
'class': 'logging.FileHandler',
'filename': os.path.join(os.path.dirname(BASE_DIR), 'web-log.log'),
'formatter': 'simple',
},
},
'root':{
'handlers':['console','file'],
'level':'INFO'
},
'loggers': {
'django': {
'handlers': ['console','file'],
'level': 'ERROR',
}
}
}
在 interview 文件夹下的 admin.py 文件添加写入日志的代码,当导出 csv 时便会记录操作
import logging
logger = logging.getLogger(__name__)
def export_model_as_csv(modeladmin,request,queryset):
...
logger.info("%s exported %s candidate records" % (request.user,len(queryset)))
return response
效果图就不展示了,大家自己操作一下就好
钉钉群消息通知
为什么不使用 Email/SMS 通知?
- 由于邮件、短信没有限制,可以给任何人发;网络上对于 API 调用有了各种限制
- 阿里云封禁 25 端口
为什么使用钉钉群消息?
- 可以使用 Web Hook 直接发送,简单易用
- 低成本
Webhook 是一个 API 概念,是微服务 API 的使用范式之一,也被成为反向 API,即前端不主动发送请求,完全由后端推送;举个常用例子,比如你的好友发了一条朋友圈,后端将这条消息推送给所有其他好友的客户端,就是 Webhook 的典型场景。
简单来说,Webhook 就是一个接收 HTTP POST(或GET,PUT,DELETE)的URL,一个实现了 Webhook 的 API 提供商就是在当事件发生的时候会向这个配置好的 URL 发送一条信息,与请求-响应式不同,使用 Webhook 你可以实时接受到变化。
对于第三方平台验权、登陆等 没有前端界面做中转的场景,或者强安全要求的支付场景等,适合用 Webhook 做数据主动推送,说白了就是在前端无从参与,或者因为前端安全问题不适合参与时,就是 Webhook 的场景;很显然 Webhook 也不是 Http 的替代品,不过的确是一种新的前后端交互方式。
其他推荐消息方式?
- Slack 消息
- 企业微信消息
安装钉钉聊天机器人
pip install DingtalkChatbot
在 interview 新建 python 文件 dingtalk
from dingtalkchatbot.chatbot import DingtalkChatbot
from django.conf import settings
def send(message, at_mobiles=[]):
#引用 settings 里面配置的钉钉群消息通知的WebHook地址:
webhook = settings.DINGTALK_WEB_HOOK
#初始化机器人小丁,#方式一:通常初始化方式
xiaoding = DingtalkChatbot(webhook)
#方式二:勾选“加签”选项时使用(v1.5以上新功能)
# xiaoding = DingtalkChatbot(webhook, secret=secret)
#Text消息所有人
xiaoding.send_text(msg=('面试通知:%s' % message),at_mobiles=at_mobiles)
定义通知面试官的方法
from interview import dingtalk
# 通知一面面试官面试
def notify_interviewer(modeladmin, request, queryset):
candidates = ""
interviewers = ""
for obj in queryset:
candidates = obj.username + ";" + candidates
interviewers = obj.first_interviewer_user.username + ";" + interviewers
# 这里的消息发送到钉钉, 或者通过 Celery 异步发送到钉钉
dingtalk.send("候选人 %s 进入面试环节,亲爱的面试官,请准备好面试: %s" % (candidates, interviewers))
#send_dingtalk_message.delay("候选人 %s 进入面试环节,亲爱的面试官,请准备好面试: %s" % (candidates, interviewers) )
#messages.add_message(request, messages.INFO, '已经成功发送面试通知')
#国际化文本
notify_interviewer.short_description = '通知一面面试官'
在钉钉群中配置聊天机器人,获得 DINGTALK_WEB_HOOK,在配置文件中配置,这里不演示,涉及安全问题
简历初评
安排一面面试官
打通简历投递与面试流程,让简历实体 (Resume) 流转到候选人实体 (Candidate)
添加一个数据操作菜单“进入面试流程”
定义 enter_interview_process方法
# action 简历评估
def enter_interview_process(modeladmin, request, queryset):
candidate_names = ""
for resume in queryset:
candidate = Candidate()
# 把 obj 对象中的所有属性拷贝到 candidate 对象中:
candidate.__dict__.update(resume.__dict__)
# 修改创建时间
candidate.created_date = datetime.now()
candidate.modified_date = datetime.now()
candidate_names = candidate.username + "," + candidate_names
candidate.creator = request.user.username
candidate.save()
messages.add_message(request, messages.INFO, '候选人: %s 已成功进入面试流程' % (candidate_names) )
enter_interview_process.short_description = u"进入面试流程"
方法逻辑: 拷贝 Resume 对象中的属性 到 Candidate, 保存 Candidate, 消息提示成功保存
注册到 ResumeAdmin 中
actions = (enter_interview_process, )
查看简历详情
在interview app中 ,使得HR能够查看应聘者的简历。
jobs app中添加 ResumeDetailView 的详情页视图,使用 Django的通用视图,继承自 DetailView
from django.views.generic.detail import DetailView
# 复用DetailView
class ResumeDetailView(DetailView):
""" 简历详情页 """
model = Resume
template_name = 'resume_detail.html'
添加 Detail 页模板: resume_detail.html
{# Load the tag library #}
{% load bootstrap4 %}
{# Load CSS and JavaScript #}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{# Display django.contrib.messages as Bootstrap alerts #}
{% bootstrap_messages %}
<h1>简历详细信息 </h1>
<div> 姓名: {{ object.username }} </div> <div>城市: {{ object.city }}</div> <div>手机号码: {{ object.phone }}</div>
<p></p>
<div>邮件地址: {{ object.email}}</div>
<div>申请职位: {{ object.apply_position}}</div>
<div>出生地: {{ object.born_address}}</div>
<div>性别: {{ object.gender}}</div>
<hr>
<div>本科学校: {{ object.bachelor_school}}</div>
<div>研究所学校: {{ object.master_school}}</div>
<div>专业: {{ object.major}}</div>
<div>学历: {{ object.degree}}</div>
<hr>
<p>候选人介绍: {{ object.candidate_introduction}}</p>
<p>工作经历: {{ object.work_experience}}</p>
<p>项目经历: {{ object.project_experience}}</p>
候选人列表页, 对于每一行来自简历投递的数据,添加一个“查看简历”的链接:
from jobs.models import Resume
from django.utils.safestring import mark_safe
list_display =('username','city','get_resume','bachelor_school','first_score','first_result','first_interviewer_user',
'second_result','second_interviewer_user','hr_score','hr_result','last_editor')
# 获取简历
def get_resume(self, obj):
if not obj.phone:
return ""
# 按手机号过滤出简历
resumes = Resume.objects.filter(phone=obj.phone)
# 当简历存在时
if resumes and len(resumes) > 0:
return mark_safe(u'<a href="/resume/%s" target="_blank">%s</a' % (resumes[0].id, "查看简历"))
return ""
get_resume.short_description = '查看简历'
# 允许HTML标签
get_resume.allow_tags = True
列表页,使用 函数名称 作为 list_display 中的字段
简历详情页路由
# 简历详情页
path('resume/<int:pk>/', views.ResumeDetailView.as_view(), name='resume-detail'),
第六阶段结束!