django-admin startproject recruitment
python manage.py startapp job
INSTALLED_APPS = [
'jobs',
]
python manage.py makemigrations
python manage.py migrate
created_date 和 modified_date 为自动添加的时间。
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
JobTypes = [
(0,"技术类"),
(1,"产品类"),
(2,"运营类"),
(3,"设计类"),
(4,"市场营销类")
]
Cities = [
(0,"北京"),
(1,"上海"),
(2,"深圳"),
(3,"杭州"),
(4,"广州")
]
class Job(models.Model):
# Translators: 职位实体的翻译
job_type = models.SmallIntegerField(blank=False, choices=JobTypes, verbose_name=("职位类别"))
job_name = models.CharField(max_length=250, blank=False, verbose_name=("职位名称"))
job_city = models.SmallIntegerField(choices=Cities, blank=False, verbose_name=("工作地点"))
job_responsibility = models.TextField(max_length=1024, verbose_name=("职位职责"))
job_requirement = models.TextField(max_length=1024, blank=False, verbose_name=("职位要求"))
creator = models.ForeignKey(User, verbose_name=("创建人"), null=True, on_delete=models.SET_NULL)
created_date = models.DateTimeField(verbose_name=("创建日期"), auto_now_add=True)
modified_date = models.DateTimeField(verbose_name=("修改日期"), auto_now=True)
class Meta:
verbose_name = ('职位')
verbose_name_plural = ('职位列表')
def __str__(self):
return self.job_name
save_model()使creator可以默认选择当前user。
from django.contrib import admin
from jobs.models import Job
class JobAdmin(admin.ModelAdmin):
exclude = ('creator','created_date','modified_date')
list_display = ('job_name', 'job_type', 'job_city', 'creator', 'created_date', 'modified_date')
def save_model(self, request, obj, form, change):
if obj.creator is None:
obj.creator = request.user
super().save_model(request, obj, form, change)
# Register your models here.
admin.site.register(Job,JobAdmin)
from django.shortcuts import render
from jobs.models import Job
from jobs.models import Cities, JobTypes
# Create your views here.
def joblist(request):
job_list = Job.objects.order_by('job_type')
context = {'job_list': job_list}
for job in job_list:
job.city_name = Cities[job.job_city][1]
job.type_name = JobTypes[job.job_type][1]
return render(request, 'joblist.html', context)
<!--jobs/templates/base.html-->
<h1 style="margin:auto;width:50%">匠果科技开放职位</h1>
<p></p>
{% block content %}
{% endblock %}
{% extends 'base.html' %}
{% block content %}
{% if job_list %}
<ul>
{% for job in job_list %}
<li>{{job.type_name}} <a href="/job/{{ job.id }}/" style="color:blue">{{ job.job_name }}</a> {{job.city_name}} </li>
{% endfor %}
</ul>
{% else %}
<p>No jobs are available.</p>
{% endif %}
{% endblock %}
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path("", include("jobs.urls")),
]
from django.urls import path
from jobs import views
urlpatterns = [
# 职位列表
path("joblist/", views.joblist, name="joblist"),
]
{% extends 'base.html' %}
{% block content %}
<div style="margin:auto; width:50%;">
{% if job %}
<div class="position_name" z>
<h2>岗位名称:{{job.job_name}} </h2>
城市:
{{job.city_name}} <p></p>
</div>
<hr>
<div class="position_responsibility" style="width:600px;">
<h3>岗位职责:</h3>
<pre style="font-size:16px">{{job.job_responsibility}}
</pre>
</div>
<hr>
<div class="position_requirement" style="width:600px; ">
<h3>任职要求:</h3>
<pre style="font-size:16px">{{job.job_requirement}}
</pre>
</div>
<div class="apply_position">
<input type="button" class="btn btn-primary" style="width:120px;" value="申请" onclick="location.href='/resume/add/?apply_position={{job.job_name}}&city={{job.city_name}}'"/>
</div>
{% else %}
<p>职位不存在</p>
{% endif %}
{% endblock %}
</div>
def detail(request, job_id):
try:
job = Job.objects.get(pk=job_id)
job.city_name = Cities[job.job_city][1]
except Job.DoesNotExist:
raise Http404("Job does not exist")
return render(request, 'job.html', {'job': job})
from django.urls import path
from jobs import views
urlpatterns = [
# 职位列表
path("joblist/", views.joblist, name="joblist"),
# 职位详情
#url(r'^job/(?P\d+)/$', views.detail, name='detail'),
path('job//' , views.detail, name='detail'),
]
两个需求可以合二为一:1)HR可以维护候选人信息;2)面试官可以维护面试反馈。
python manage.py startapp interview
INSTALLED_APPS = [
......
'interview',
......
]
# 候选人学历
DEGREE_TYPE = ((u'本科', u'本科'), (u'硕士', u'硕士'), (u'博士', u'博士'))
from django.db import models
from django.contrib.auth.models import User
from jobs.models import DEGREE_TYPE
# 第一轮面试结果
FIRST_INTERVIEW_RESULT_TYPE = ((u'建议复试', u'建议复试'), (u'待定', u'待定'), (u'放弃', u'放弃'))
# 复试面试建议
INTERVIEW_RESULT_TYPE = ((u'建议录用', u'建议录用'), (u'待定', u'待定'), (u'放弃', u'放弃'))
# HR终面结论
HR_SCORE_TYPE = (('S', 'S'), ('A', 'A'), ('B', 'B'), ('C', 'C'))
class Candidate(models.Model):
# 基础信息
userid = models.IntegerField(unique=True, blank=True, null=True, verbose_name=u'应聘者ID')
username = models.CharField(max_length=135, verbose_name=u'姓名')
city = models.CharField(max_length=135, verbose_name=u'城市')
phone = models.CharField(max_length=135, verbose_name=u'手机号码')
email = models.EmailField(max_length=135, blank=True, verbose_name=u'邮箱')
apply_position = models.CharField(max_length=135, blank=True, verbose_name=u'应聘职位')
born_address = models.CharField(max_length=135, blank=True, verbose_name=u'生源地')
gender = models.CharField(max_length=135, blank=True, verbose_name=u'性别')
candidate_remark = models.CharField(max_length=135, blank=True, verbose_name=u'候选人信息备注')
# 学校与学历信息
bachelor_school = models.CharField(max_length=135, blank=True, verbose_name=u'本科学校')
master_school = models.CharField(max_length=135, blank=True, verbose_name=u'研究生学校')
doctor_school = models.CharField(max_length=135, blank=True, verbose_name=u'博士生学校')
major = models.CharField(max_length=135, blank=True, verbose_name=u'专业')
degree = models.CharField(max_length=135, choices=DEGREE_TYPE, blank=True, verbose_name=u'学历')
# 综合能力测评成绩,笔试测评成绩
test_score_of_general_ability = models.DecimalField(decimal_places=1, null=True, max_digits=3, blank=True,
verbose_name=u'综合能力测评成绩')
paper_score = models.DecimalField(decimal_places=1, null=True, max_digits=3, blank=True, verbose_name=u'笔试成绩')
# 第一轮面试记录
first_score = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True, verbose_name=u'初试分',
help_text=u'1-5分,极优秀: >=4.5,优秀: 4-4.4,良好: 3.5-3.9,一般: 3-3.4,较差: <3分')
first_learning_ability = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
verbose_name=u'学习能力得分')
first_professional_competency = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
verbose_name=u'专业能力得分')
first_advantage = models.TextField(max_length=1024, blank=True, verbose_name=u'优势')
first_disadvantage = models.TextField(max_length=1024, blank=True, verbose_name=u'顾虑和不足')
first_result = models.CharField(max_length=256, choices=FIRST_INTERVIEW_RESULT_TYPE, blank=True,
verbose_name=u'初试结果')
first_recommend_position = models.CharField(max_length=256, blank=True, verbose_name=u'推荐部门')
first_interviewer_user = models.ForeignKey(User, related_name='first_interviewer_user', blank=True, null=True, on_delete=models.CASCADE, verbose_name=u'面试官')
first_remark = models.CharField(max_length=135, blank=True, verbose_name=u'初试备注')
# 第二轮面试记录
second_score = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True, verbose_name=u'专业复试得分',
help_text=u'1-5分,极优秀: >=4.5,优秀: 4-4.4,良好: 3.5-3.9,一般: 3-3.4,较差: <3分')
second_learning_ability = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
verbose_name=u'学习能力得分')
second_professional_competency = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
verbose_name=u'专业能力得分')
second_pursue_of_excellence = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
verbose_name=u'追求卓越得分')
second_communication_ability = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
verbose_name=u'沟通能力得分')
second_pressure_score = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True,
verbose_name=u'抗压能力得分')
second_advantage = models.TextField(max_length=1024, blank=True, verbose_name=u'优势')
second_disadvantage = models.TextField(max_length=1024, blank=True, verbose_name=u'顾虑和不足')
second_result = models.CharField(max_length=256, choices=INTERVIEW_RESULT_TYPE, blank=True, verbose_name=u'专业复试结果')
second_recommend_position = models.CharField(max_length=256, blank=True, verbose_name=u'建议方向或推荐部门')
second_interviewer_user = models.ForeignKey(User, related_name='second_interviewer_user', blank=True, null=True, on_delete=models.CASCADE, verbose_name=u'二面面试官')
second_remark = models.CharField(max_length=135, blank=True, verbose_name=u'专业复试备注')
# HR终面
hr_score = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True, verbose_name=u'HR复试综合等级')
hr_responsibility = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True, verbose_name=u'HR责任心')
hr_communication_ability = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True,
verbose_name=u'HR坦诚沟通')
hr_logic_ability = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True, verbose_name=u'HR逻辑思维')
hr_potential = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True, verbose_name=u'HR发展潜力')
hr_stability = models.CharField(max_length=10, choices=HR_SCORE_TYPE, blank=True, verbose_name=u'HR稳定性')
hr_advantage = models.TextField(max_length=1024, blank=True, verbose_name=u'优势')
hr_disadvantage = models.TextField(max_length=1024, blank=True, verbose_name=u'顾虑和不足')
hr_result = models.CharField(max_length=256, choices=INTERVIEW_RESULT_TYPE, blank=True, verbose_name=u'HR复试结果')
hr_interviewer_user = models.ForeignKey(User, related_name='hr_interviewer_user', blank=True, null=True, on_delete=models.CASCADE, verbose_name=u'HR面试官')
hr_remark = models.CharField(max_length=256, blank=True, verbose_name=u'HR复试备注')
creator = models.CharField(max_length=256, blank=True, verbose_name=u'候选人数据的创建人')
created_date = models.DateTimeField(auto_now_add=True, verbose_name=u'创建时间')
modified_date = models.DateTimeField(auto_now=True, null=True, blank=True, verbose_name=u'更新时间')
last_editor = models.CharField(max_length=256, blank=True, verbose_name=u'最后编辑者')
class Meta:
db_table = u'candidate'
verbose_name = u'应聘者'
verbose_name_plural = u'应聘者'
# Python 3 直接定义 __str__() 方法即可,系统使用这个方法来把对象转换成字符串
def __str__(self):
return self.username
fieldsets的快速设定方法:填写fieldsets时,可把models的字段全部拷贝进去再删除。
from django.contrib import admin
from interview.models import Candidate
# Register your models here.
# 候选人管理类
class CandidateAdmin(admin.ModelAdmin):
exclude = ('creator', 'created_date', 'modified_date')
list_display = (
'username', 'city', 'bachelor_school', 'first_score', 'first_result', 'first_interviewer_user', 'second_score',
'second_result', 'second_interviewer_user', 'hr_score', 'hr_result', 'hr_interviewer_user',)
# 分组展示字段,分三块,基础信息、第一轮面试记录、第二轮面试(专业复试)、HR复试
fieldsets = (
(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",)}),
('第一轮面试', {'fields': (
("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage",
"first_result", "first_recommend_position", "first_interviewer_user", "first_remark",)}),
('第二轮面试(专业复试)', {'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_user", "second_remark",)}),
('HR复试', {'fields': (
"hr_score", ("hr_responsibility", "hr_communication_ability", "hr_logic_ability"), ("hr_potential", "hr_stability"),
"hr_advantage", "hr_disadvantage", "hr_result", "hr_interviewer_user", "hr_remark",)}),
)
admin.site.register(Candidate, CandidateAdmin)
可以使用python manage.py import_candidates --path /path/to/your/file.csv来批量导入信息。
import csv
from django.core.management import BaseCommand
from interview.models import Candidate
# run command to import candidates:
# python manage.py import_candidates --path /path/to/your/file.csv
class Command(BaseCommand):
help = '从一个CSV文件的内容中读取候选人列表,导入到数据库中'
def add_arguments(self, parser):
parser.add_argument('--path', type=str)
def handle(self, *args, **kwargs):
path = kwargs['path']
with open(path, 'rt', encoding="gbk") as f:
reader = csv.reader(f, dialect='excel', delimiter=';')
for row in reader:
candidate = Candidate.objects.create(
username=row[0],
city=row[1],
phone=row[2],
bachelor_school=row[3],
major=row[4],
degree=row[5],
test_score_of_general_ability=row[6],
paper_score=row[7]
)
print(candidate)
C:\Users\Season\Desktop\4.python网页前后端\Django基础教程\workspace4-recruiting\recruitment【13-】>python manage.py import_candidates --path candidates.csv
刘倩
陈欣欣
刘德华
李小龙
新增以下代码
# 右侧筛选条件
list_filter = ('city','first_result','second_result','hr_result','first_interviewer_user','second_interviewer_user','hr_interviewer_user')
# 查询字段
search_fields = ('username', 'phone', 'email', 'bachelor_school')
### 列表页排序字段
ordering = ('hr_result','second_result','first_result',)
变更后的admin.py
from django.contrib import admin
from interview.models import Candidate
# Register your models here.
# 候选人管理类
class CandidateAdmin(admin.ModelAdmin):
exclude = ('creator', 'created_date', 'modified_date')
list_display = (
'username', 'city', 'bachelor_school', 'first_score', 'first_result', 'first_interviewer_user', 'second_score',
'second_result', 'second_interviewer_user', 'hr_score', 'hr_result', 'hr_interviewer_user',)
# 右侧筛选条件
list_filter = ('city','first_result','second_result','hr_result','first_interviewer_user','second_interviewer_user','hr_interviewer_user')
# 查询字段
search_fields = ('username', 'phone', 'email', 'bachelor_school')
### 列表页排序字段
ordering = ('hr_result','second_result','first_result',)
# 分组展示字段,分三块,基础信息、第一轮面试记录、第二轮面试(专业复试)、HR复试
fieldsets = (
(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",)}),
('第一轮面试', {'fields': (
("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage",
"first_result", "first_recommend_position", "first_interviewer_user", "first_remark",)}),
('第二轮面试(专业复试)', {'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_user", "second_remark",)}),
('HR复试', {'fields': (
"hr_score", ("hr_responsibility", "hr_communication_ability", "hr_logic_ability"), ("hr_potential", "hr_stability"),
"hr_advantage", "hr_disadvantage", "hr_result", "hr_interviewer_user", "hr_remark",)}),
)
admin.site.register(Candidate, CandidateAdmin)
#admin.site.register(Candidate)
django链接
其他参考链接添加链接描述
response.charset = ‘utf-8-sig’ # 可选, 修改编码为带BOM的utf-8格式(Excel打开不会有乱码)
新增export_model_as_csv()、exportable_fields ,将actions = (export_model_as_csv, )加进去class CandidateAdmin。
from django.contrib import admin
from django.http import HttpResponse
from interview.models import Candidate
from datetime import datetime
import csv
# Register your models here.
exportable_fields = ('username', 'city', 'phone', 'bachelor_school', 'master_school', 'degree', 'first_result', 'first_interviewer_user',
'second_result', 'second_interviewer_user', 'hr_result', 'hr_score', 'hr_remark', 'hr_interviewer_user')
# define export action
def export_model_as_csv(modeladmin, request, queryset):
response = HttpResponse(content_type='text/csv')
field_list = exportable_fields
response['Content-Disposition'] = 'attachment; filename=%s-list-%s.csv' % (
'recruitment-candidates',
datetime.now().strftime('%Y-%m-%d-%H-%M-%S'),
)
# 写入表头
response.charset = 'utf-8-sig' # 可选, 修改编码为带BOM的utf-8格式(Excel打开不会有乱码)
writer = csv.writer(response)
writer.writerow(
[queryset.model._meta.get_field(f).verbose_name.title() for f in field_list],
)
for obj in queryset:
## 单行 的记录(各个字段的值), 根据字段对象,从当前实例 (obj) 中获取字段值
csv_line_values = []
for field in field_list:
field_object = queryset.model._meta.get_field(field)
field_value = field_object.value_from_object(obj)
csv_line_values.append(field_value)
writer.writerow(csv_line_values)
return response
export_model_as_csv.short_description = u'导出为CSV文件'
# 候选人管理类
class CandidateAdmin(admin.ModelAdmin):
exclude = ('creator', 'created_date', 'modified_date')
actions = (export_model_as_csv, )
list_display = (
'username', 'city', 'bachelor_school', 'first_score', 'first_result', 'first_interviewer_user', 'second_score',
'second_result', 'second_interviewer_user', 'hr_score', 'hr_result', 'hr_interviewer_user',)
# 右侧筛选条件
list_filter = ('city','first_result','second_result','hr_result','first_interviewer_user','second_interviewer_user','hr_interviewer_user')
# 查询字段
search_fields = ('username', 'phone', 'email', 'bachelor_school')
### 列表页排序字段
ordering = ('hr_result','second_result','first_result',)
# 分组展示字段,分三块,基础信息、第一轮面试记录、第二轮面试(专业复试)、HR复试
fieldsets = (
(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",)}),
('第一轮面试', {'fields': (
("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage",
"first_result", "first_recommend_position", "first_interviewer_user", "first_remark",)}),
('第二轮面试(专业复试)', {'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_user", "second_remark",)}),
('HR复试', {'fields': (
"hr_score", ("hr_responsibility", "hr_communication_ability", "hr_logic_ability"), ("hr_potential", "hr_stability"),
"hr_advantage", "hr_disadvantage", "hr_result", "hr_interviewer_user", "hr_remark",)}),
)
admin.site.register(Candidate, CandidateAdmin)
#admin.site.register(Candidate)
https://docs.djangoproject.com/zh-hans/3.1/topics/logging/#topic-logging-parts-handlers
当logger中的django_python3_ldap的level在DEBUG以上,就调用handlers–“console”。而handlers已经定义了指定的输出方式。而formatter是指定输出格式。
# 日志
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
"django_python3_ldap": {
"handlers": ["console"],
"level": "DEBUG",
},
},
}
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': { # exact format is not important, this is the minimum information
'format': '%(asctime)s %(name)-12s %(lineno)d %(levelname)-8s %(message)s',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'simple',
},
'mail_admins': { # Add Handler for mail_admins for `warning` and above
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
},
'file': {
#'level': 'INFO',
'class': 'logging.FileHandler',
'formatter': 'simple',
'filename': os.path.join(LOG_DIR, 'recruitment.admin.log'),
},
'performance': {
#'level': 'INFO',
'class': 'logging.FileHandler',
'formatter': 'simple',
'filename': os.path.join(LOG_DIR, 'recruitment.performance.log'),
},
},
'root': {
'handlers': ['console', 'file'],
'level': 'INFO',
},
'loggers': {
"django_python3_ldap": {
"handlers": ["console", "file"],
"level": "DEBUG",
},
"interview.performance": {
"handlers": ["console", "performance"],
"level": "INFO",
"propagate": False,
},
'django': {
"handlers": ["console","file"],
"level": "INFO",
'propagate': True,
},
},
}
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',},
'file':{'class':'logging.FileHandler','formatter':'simple','filename':os.path.join(LOG_DIR,'recruitment.admin.log')},
},
'root':{
'handlers':['console','file'],
'level':'INFO',
},
}
备注:这里默认会调用root。不会使用loggers里面的如interview.performance。
注意logger = logging.getLogger( name )和logger.error(" %s has exported %s candidate records" % (request.user.username, len(queryset)))
from django.contrib import admin
from django.http import HttpResponse
from interview.models import Candidate
from datetime import datetime
import csv
import logging
logger = logging.getLogger(__name__)
exportable_fields = ('username', 'city', 'phone', 'bachelor_school', 'master_school', 'degree', 'first_result', 'first_interviewer_user',
'second_result', 'second_interviewer_user', 'hr_result', 'hr_score', 'hr_remark', 'hr_interviewer_user')
# define export action
def export_model_as_csv(modeladmin, request, queryset):
response = HttpResponse(content_type='text/csv')
field_list = exportable_fields
response['Content-Disposition'] = 'attachment; filename=%s-list-%s.csv' % (
'recruitment-candidates',
datetime.now().strftime('%Y-%m-%d-%H-%M-%S'),
)
# 写入表头
writer = csv.writer(response)
writer.writerow(
[queryset.model._meta.get_field(f).verbose_name.title() for f in field_list],
)
for obj in queryset:
## 单行 的记录(各个字段的值), 根据字段对象,从当前实例 (obj) 中获取字段值
csv_line_values = []
for field in field_list:
field_object = queryset.model._meta.get_field(field)
field_value = field_object.value_from_object(obj)
csv_line_values.append(field_value)
writer.writerow(csv_line_values)
logger.error(" %s has exported %s candidate records" % (request.user.username, len(queryset)))
return response
export_model_as_csv.short_description = u'导出为CSV文件'
2021-11-16 07:30:11,714 django.utils.autoreload 613 INFO Watching for file changes with StatReloader
2021-11-16 07:30:11,714 django.utils.autoreload 613 INFO Watching for file changes with StatReloader
2021-11-16 07:30:58,594 django.server 157 INFO "GET /admin/interview/candidate/ HTTP/1.1" 200 15726
2021-11-16 07:30:58,594 django.server 157 INFO "GET /admin/interview/candidate/ HTTP/1.1" 200 15726
2021-11-16 07:31:03,627 interview.admin 38 ERROR season has exported 5 candidate records
2021-11-16 07:31:03,629 django.server 157 INFO "POST /admin/interview/candidate/ HTTP/1.1" 200 496
2021-11-16 07:31:03,629 django.server 157 INFO "POST /admin/interview/candidate/ HTTP/1.1" 200 496
简单来说,就是base是基类,然后python manage runserver时候切换local或production环境的设定,如果字典没有设定值,就采用base基类的默认值。
os.environ.setdefault(‘DJANGO_SETTINGS_MODULE’, ‘settings.base’)
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
#os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'recruitment.settings')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings.base')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
from .base import *
DEBUG = True
ALLOWED_HOSTS = ["recruit.ihopeit.com","127.0.0.1"]
其中,DEBUG可以设定为False。
from .base import *
DEBUG = False
ALLOWED_HOSTS = ["recruit.ihopeit.com","127.0.0.1"]
python manage.py runserver --settings=settings.production
python manage.py runserver --settings=settings.local
"""
Django settings for recruitment project.
Generated by 'django-admin startproject' using Django 3.2.7.
For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
LOG_DIR = os.path.dirname(BASE_DIR)
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-s=_#6o=h)t_2*c^sor=1gtmrpa(5&oie+k_ilxh$7#&&^9z$l6'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'jobs',
'interview',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'recruitment.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'recruitment.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# 日志
# LOGGING = {
# 'version': 1,
# 'disable_existing_loggers': False,
# 'handlers': {
# 'console': {
# 'class': 'logging.StreamHandler',
# },
# },
# 'loggers': {
# "django_python3_ldap": {
# "handlers": ["console"],
# "level": "DEBUG",
# },
# },
# }
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'simple': { # exact format is not important, this is the minimum information
'format': '%(asctime)s %(name)-12s %(lineno)d %(levelname)-8s %(message)s',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'simple',
},
'mail_admins': { # Add Handler for mail_admins for `warning` and above
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
},
'file': {
#'level': 'INFO',
'class': 'logging.FileHandler',
'formatter': 'simple',
'filename': os.path.join(LOG_DIR, 'recruitment.admin.log'),
},
'performance': {
#'level': 'INFO',
'class': 'logging.FileHandler',
'formatter': 'simple',
'filename': os.path.join(LOG_DIR, 'recruitment.performance.log'),
},
},
'root': {
'handlers': ['console', 'file'],
'level': 'INFO',
},
'loggers': {
"django_python3_ldap": {
"handlers": ["console", "file"],
"level": "DEBUG",
},
"interview.performance": {
"handlers": ["console", "performance"],
"level": "INFO",
"propagate": False,
},
'django': {
"handlers": ["console","file"],
"level": "INFO",
'propagate': True,
},
},
}
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
STATIC_URL = '/static/'
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
admin.site.site_header = _('招聘管理系统')
first_score = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True, verbose_name=u'初试分',help_text=u'1-5分,极优秀: >=4.5,优秀: 4-4.4,良好: 3.5-3.9,一般: 3-3.4,较差: <3分')
second_score = models.DecimalField(decimal_places=1, null=True, max_digits=2, blank=True, verbose_name=u'专业复试得分', help_text=u'1-5分,极优秀: >=4.5,优秀: 4-4.4,良好: 3.5-3.9,一般: 3-3.4,较差: <3分')
first_interviewer_user = models.ForeignKey(User, related_name='first_interviewer_user', blank=True, null=True, on_delete=models.CASCADE, verbose_name=u'一面面试官')
second_interviewer_user = models.ForeignKey(User, related_name='second_interviewer_user', blank=True, null=True, on_delete=models.CASCADE, verbose_name=u'二面面试官')
hr_interviewer_user = models.ForeignKey(User, related_name='hr_interviewer_user', blank=True, null=True, on_delete=models.CASCADE, verbose_name=u'HR面试官')
# 候选人管理类
class CandidateAdmin(admin.ModelAdmin):
### 设定只读字段
#readonly_fields = ('first_interviewer_user','second_interviewer_user',)
def get_group_names(self, user):
group_names = []
for g in user.groups.all():
group_names.append(g.name)
return group_names
def get_readonly_fields(self, request, obj):
group_names = self.get_group_names(request.user)
if 'interviewer' in group_names:
logger.info("interviewer is in user's group for %s" % request.user.username)
return ('first_interviewer_user','second_interviewer_user',)
return ()
### HR在列表页直接编辑面试官信息
default_list_editable = ('first_interviewer_user','second_interviewer_user',)
def get_list_editable(self, request):
group_names = self.get_group_names(request.user)
if request.user.is_superuser or 'hr' in group_names:
return self.default_list_editable
return ()
def get_changelist_instance(self, request):
self.list_editable = self.get_list_editable(request)
return super().get_changelist_instance(request)
def get_readonly_fields(self, request, obj=None):
"""
Hook for specifying custom readonly fields.
"""
return self.readonly_fields
def get_changelist_instance(self, request):
"""
Return a `ChangeList` instance based on `request`. May raise
`IncorrectLookupParameters`.
"""
list_display = self.get_list_display(request)
list_display_links = self.get_list_display_links(request, list_display)
# Add the action checkboxes if any actions are available.
if self.get_actions(request):
list_display = ['action_checkbox', *list_display]
sortable_by = self.get_sortable_by(request)
ChangeList = self.get_changelist(request)
return ChangeList(
request,
self.model,
list_display,
list_display_links,
self.get_list_filter(request),
self.date_hierarchy,
self.get_search_fields(request),
self.get_list_select_related(request),
self.list_per_page,
self.list_max_show_all,
self.list_editable,
self,
sortable_by,
)
C:\Users\Season>pip install -i https://pypi.tuna.tsinghua.edu.cn/simple django-grappelli
# Application definition
INSTALLED_APPS = [
'grappelli',
'django.contrib.admin',
......
]
path('grappelli/', include("grappelli.urls")),
path('admin/', admin.site.urls),
重写get_fieldsets()方法。
# 候选人管理类
class CandidateAdmin(admin.ModelAdmin):
# 分组展示字段,分三块,基础信息、第一轮面试记录、第二轮面试(专业复试)、HR复试
default_fieldsets = (
(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",)}),
('第一轮面试', {'fields': (
("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage",
"first_result", "first_recommend_position", "first_interviewer_user", "first_remark",)}),
('第二轮面试(专业复试)', {'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_user", "second_remark",)}),
('HR复试', {'fields': (
"hr_score", ("hr_responsibility", "hr_communication_ability", "hr_logic_ability"), ("hr_potential", "hr_stability"),
"hr_advantage", "hr_disadvantage", "hr_result", "hr_interviewer_user", "hr_remark",)}),
)
# 一面面试官字段
default_fieldsets_first = (
(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",)}),
('第一轮面试', {'fields': (
("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage",
"first_result", "first_recommend_position", "first_interviewer_user", "first_remark",)}),
)
# 二面面试官字段
default_fieldsets_second = (
(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",)}),
('第二轮面试(专业复试)', {'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_user", "second_remark",)}),
)
# 一面面试官只可以修改一面信息,二面面试官只可以修改二面信息
def get_fieldsets(self, request, obj):
group_names = self.get_group_names(request.user)
if 'interviewer' in group_names and obj.first_interviewer_user == request.user:
return self.default_fieldsets_first
if 'interviewer' in group_names and obj.second_interviewer_user == request.user:
return self.default_fieldsets_second
return self.default_fieldsets
import interview.candidate_fieldsets as cf
# 候选人管理类
class CandidateAdmin(admin.ModelAdmin):
# 一面面试官只可以修改一面信息,二面面试官只可以修改二面信息
def get_fieldsets(self, request, obj):
group_names = self.get_group_names(request.user)
if 'interviewer' in group_names and obj.first_interviewer_user == request.user:
#return self.default_fieldsets_first
return cf.default_fieldsets_first
if 'interviewer' in group_names and obj.second_interviewer_user == request.user:
#return self.default_fieldsets_second
return cf.default_fieldsets_second
#return self.default_fieldsets
return cf.default_fieldsets
# 分组展示字段,分三块,基础信息、第一轮面试记录、第二轮面试(专业复试)、HR复试
default_fieldsets = (
(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",)}),
('第一轮面试', {'fields': (
("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage",
"first_result", "first_recommend_position", "first_interviewer_user", "first_remark",)}),
('第二轮面试(专业复试)', {'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_user", "second_remark",)}),
('HR复试', {'fields': (
"hr_score", ("hr_responsibility", "hr_communication_ability", "hr_logic_ability"), ("hr_potential", "hr_stability"),
"hr_advantage", "hr_disadvantage", "hr_result", "hr_interviewer_user", "hr_remark",)}),
)
# 一面面试官字段
default_fieldsets_first = (
(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",)}),
('第一轮面试', {'fields': (
("first_score", "first_learning_ability", "first_professional_competency"), "first_advantage", "first_disadvantage",
"first_result", "first_recommend_position", "first_interviewer_user", "first_remark",)}),
)
# 二面面试官字段
default_fieldsets_second = (
(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",)}),
('第二轮面试(专业复试)', {'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_user", "second_remark",)}),
)
重写get_queryset()方法
from django.db.models import Q
# 候选人管理类
class CandidateAdmin(admin.ModelAdmin):
# 对于非管理员,非HR,获取自己是一面面试官或者二面面试官的候选人集合:s
def get_queryset(self, request): # show data only owned by the user
qs = super(CandidateAdmin, self).get_queryset(request)
group_names = self.get_group_names(request.user)
if request.user.is_superuser or 'hr' in group_names:
return qs
return Candidate.objects.filter(Q(first_interviewer_user=request.user) | Q(second_interviewer_user=request.user))
class Candidate(models.Model):
class Meta:
db_table = u'candidate'
verbose_name = u'应聘者'
verbose_name_plural = u'应聘者'
#增加候选人的权限
permissions = [
("export", "Can export candidate list"),
("notify", "notify interviewer for candidate review"),
]
# 增加导出权限管控
export_model_as_csv.allowed_permissions = ('export',)
# 候选人管理类
class CandidateAdmin(admin.ModelAdmin):
# 当前用户是否有导出权限:
def has_export_permission(self, request):
opts = self.opts
return request.user.has_perm('%s.%s' % (opts.app_label, "export"))
#coding=utf-8
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 .base import *
DEBUG = True
ALLOWED_HOSTS = ["recruit.ihopeit.com","127.0.0.1"]
## 务必修改以下值,确保运行时系统安全:
SECRET_KEY = "w$46bks+b3-7f(13#i%v@jwejrnxc$^^#@#@^t@fofizy1^mo9r8(-939243423300"
## 如果仅使用数据库中的账号,以下 LDAP 配置可忽略
## 替换这里的配置为正确的域服务器配置,同时可能需要修改 base.py 中的 LDAP 服务器相关配置:
LDAP_AUTH_URL = "ldap://xxxxx:389"
LDAP_AUTH_CONNECTION_USERNAME = "admin"
LDAP_AUTH_CONNECTION_PASSWORD = "your_admin_credentials"
INSTALLED_APPS += (
# other apps for production site
)
## 钉钉群的 WEB_HOOK, 用于发送钉钉消息
DINGTALK_WEB_HOOK = "https://oapi.dingtalk.com/robot/send?access_token=***********************"
C:\Users\Season>cd C:\Users\Season\Desktop\4.python网页前后端\Django基础教程\workspace4-recruiting\recruitment【23】
C:\Users\Season\Desktop\4.python网页前后端\Django基础教程\workspace4-recruiting\recruitment【23】>python manage.py shell --settings=settings.local
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 7.14.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from interview import dingtalk
In [2]: dingtalk.send("通知12314134")
In [3]:
# 通知一面面试官面试
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) )
notify_interviewer.short_description = u'通知一面面试官'
# 候选人管理类
class CandidateAdmin(admin.ModelAdmin):
actions = (export_model_as_csv, notify_interviewer, )
其中需要使用pip直接安装最新的django-registration-redux-2.9。如果使用清华镜像会失败pip install -i https://pypi.tuna.tsinghua.edu.cn/simple django-registration-redux。
- 安装应用
pip install django-registration-redux
- 在settings.base 中install app
'registration', # 用户登陆注册功能
- 有新的库表数据,需要迁移
python manage.py makemigrations/ python manage.py migrate
项目url设置登陆url: path('accounts/', include('registration.backends.simple.urls')),
先到django后台将用户登出,然后访问:/accounts/register/来注册用户
accounts/login/
输入用户名密码登陆
# 登陆后跳转首页
LOGIN_REDIRECT_URL = '/'
# 注册后跳转登陆
SIMPLE_BACKEND_REDIRECT_URL = '/accounts/login/'
项目url(recrument.urls): url(r"^", include("jobs.urls")),
应用url(jobs.urls): path("", views.joblist, name="name"),
class Resume(models.Model):
# Translators: 简历实体的翻译
username = models.CharField(max_length=135, verbose_name=_('姓名'))
applicant = models.ForeignKey(User, verbose_name=_("申请人"), null=True, on_delete=models.SET_NULL)
city = models.CharField(max_length=135, verbose_name=_('城市'))
phone = models.CharField(max_length=135, verbose_name=_('手机号码'))
email = models.EmailField(max_length=135, blank=True, verbose_name=_('邮箱'))
apply_position = models.CharField(max_length=135, blank=True, verbose_name=_('应聘职位'))
born_address = models.CharField(max_length=135, blank=True, verbose_name=_('生源地'))
gender = models.CharField(max_length=135, blank=True, verbose_name=_('性别'))
picture = models.ImageField(upload_to='images/', blank=True, verbose_name=_('个人照片'))
attachment = models.FileField(upload_to='file/', blank=True, verbose_name=_('简历附件'))
# 学校与学历信息
bachelor_school = models.CharField(max_length=135, blank=True, verbose_name=_('本科学校'))
master_school = models.CharField(max_length=135, blank=True, verbose_name=_('研究生学校'))
doctor_school = models.CharField(max_length=135, blank=True, verbose_name=u'博士生学校')
major = models.CharField(max_length=135, blank=True, verbose_name=_('专业'))
degree = models.CharField(max_length=135, choices=DEGREE_TYPE, blank=True, verbose_name=_('学历'))
created_date = models.DateTimeField(verbose_name="创建日期", default=datetime.now)
modified_date = models.DateTimeField(verbose_name="修改日期", auto_now=True)
# 候选人自我介绍,工作经历,项目经历
candidate_introduction = models.TextField(max_length=1024, blank=True, verbose_name=u'自我介绍')
work_experience = models.TextField(max_length=1024, blank=True, verbose_name=u'工作经历')
project_experience = models.TextField(max_length=1024, blank=True, verbose_name=u'项目经历')
class Meta:
verbose_name = _('简历')
verbose_name_plural = _('简历列表')
def __str__(self):
return self.username
class ResumeAdmin(admin.ModelAdmin):
list_display = ('username', 'applicant', 'city', 'apply_position', 'bachelor_school', 'master_school', 'major','created_date')
readonly_fields = ('applicant', 'created_date', 'modified_date',)
fieldsets = (
(None, {'fields': (
"applicant", ("username", "city", "phone"),
("email", "apply_position", "born_address", "gender", ), ("picture", "attachment",),
("bachelor_school", "master_school"), ("major", "degree"), ('created_date', 'modified_date'),
"candidate_introduction", "work_experience","project_experience",)}),
)
def save_model(self, request, obj, form, change):
obj.applicant = request.user
super().save_model(request, obj, form, change)
# Register your models here.
admin.site.register(Job,JobAdmin)
admin.site.register(Resume, ResumeAdmin)
<h1 style="margin:auto;width:50%">匠果科技开放职位h1>
<p>p>
{% block header %}
<a href="/" style="text-decoration: none; color:#007bff">Homepagea>
<a href="/joblist" style="text-decoration: none; color:#007bff">job_lista>
{% if user.is_authenticated %}
<a href="/accounts/logout" style="text-decoration: none; color:#007bff">Logouta>
{% else %}
<a href="/accounts/login" style="text-decoration: none; color:#007bff">Logina>
{% endif %}
{% if user.is_authenticated %}
<p>终于等到你 {{ user_name }}, 期待加入我们,用技术去探索一个新世界p>
{% else %}
<br>"欢迎你,期待加入我们,登陆后可以提交简历."<br>
{% endif %}
{% endblock %}
{% block content %}
{% endblock %}
<h2>提交简历h2>
<form method="post" style="width:600px;margin-left:5px">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="提交">
form>
class ResumeCreateView(LoginRequiredMixin, CreateView):
""" 简历职位页面 """
template_name = 'resume_form.html'
success_url = '/joblist/'
model = Resume
fields = ["username", "city", "phone",
"email", "apply_position", "gender",
"bachelor_school", "master_school", "major", "degree", "picture", "attachment",
"candidate_introduction", "work_experience", "project_experience"]
## 从 URL 请求参数带入默认值
def get_initial(self):
initial = {}
for x in self.request.GET:
initial[x] = self.request.GET[x]
return initial
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.applicant = self.request.user
self.object.save()
return HttpResponseRedirect(self.get_success_url())
# 提交简历
path('resume/add/',views.ResumeCreateView.as_view(),name='resume-add'),
INSTALLED_APPS = [
'grappelli',
'bootstrap4',
'registration',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'jobs',
'interview',
]
{# Load the tag library #}
{% load bootstrap4 %}
{% load i18n %}
{# Load CSS and JavaScript #}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{# Display django.contrib.messages as Bootstrap alerts #}
{% bootstrap_messages %}
{# Load the tag library #}
{% load bootstrap4 %}
{% load i18n %}
{# Load CSS and JavaScript #}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{# Display django.contrib.messages as Bootstrap alerts #}
{% bootstrap_messages %}
<input type="button" class="btn btn-danger" style="width:120px;" value="申请" onclick="location.href='/resume/add/?apply_position={{job.job_name}}&city={{job.city_name}}'"/>
from django.contrib import admin
from jobs.models import Job,Resume
from django.contrib import messages
from interview.models import Candidate
from datetime import datetime
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"进入面试流程"
添加actions = (enter_interview_process,)
class ResumeAdmin(admin.ModelAdmin):
actions = (enter_interview_process,)
list_display = ('username', 'applicant', 'city', 'apply_position', 'bachelor_school', 'master_school', 'major','created_date')
readonly_fields = ('applicant', 'created_date', 'modified_date',)
fieldsets = (
(None, {'fields': (
"applicant", ("username", "city", "phone"),
("email", "apply_position", "born_address", "gender", ), ("picture", "attachment",),
("bachelor_school", "master_school"), ("major", "degree"), ('created_date', 'modified_date'),
"candidate_introduction", "work_experience","project_experience",)}),
)
def save_model(self, request, obj, form, change):
obj.applicant = request.user
super().save_model(request, obj, form, change)
class ResumeDetailView(DetailView):
""" 简历详情页 """
model = Resume
template_name = '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>
# 查看简历
path('resume//' , views.ResumeDetailView.as_view(), name='resume-detail'),
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'%s % (resumes[0].id, "查看简历"))
return ""
get_resume.short_description = '查看简历'
get_resume.allow_tags = True