文章目录
一、产品细节完善
1) 设置站点标题,在项目目录下的url.py
加上如下代码
from django.utils.translation import gettext as _ # 国际化 # 国际化 网页标题 admin.site.site_header = _('霍格沃兹学院') # 变成key 对于其他语言的value # 国际化 网站标题 admin.site.site_title = _('霍格沃兹招聘信息网')
2) 填写信息显示提示
- 添加模型中的
model
help_text
# 第一轮面试结果 first_score = models.DecimalField(max_digits=3, decimal_places=1, blank=True, verbose_name='初始分', null=True,help_text=_('1~5分,非常优秀:>4.5'))
3) 将面试官与候选人关联
我们希望能够由HR直接可以下拉选择 面试官所有用户选择,而不能由面试官自己选择。
- 方法一(不推荐!)
在model 修改原字段类型为 foreignkey
(注意! 此方法会涉及到数据迁移,此时更改数据结构可能会报错)
- 方法二 (推荐)
保留或者删除原有字段(建议删除,如果删除在admin.py
显示字段list_play
也要修改),然后添加新的字段做外键的引用
··· # 第一轮面试结果 first_score = models.DecimalField(max_digits=3, decimal_places=1, blank=True, verbose_name='初始分', null=True,help_text=_('1~5分,非常优秀:>4.5')) first_result = models.CharField(choices=FIRST_INTERVIEW_SCORE_TYPE, blank=True, verbose_name='初始结果', max_length=135) # first_interviewer = models.CharField(max_length=135, blank=True, verbose_name='面试官') first_interviewer_user = models.ForeignKey(User,related_name='first_interviewer_user',on_delete=models.CASCADE,blank=True, verbose_name=_('一面面试官'),null=True) # 第二轮面试结果 second_score = models.DecimalField(max_digits=3, decimal_places=1, blank=True, verbose_name='初始分', null=True,help_text=_('1~5分')) second_result = models.CharField(choices=INTERVIEW_RESULT_TYPE, blank=True, verbose_name='复试结果', max_length=135) # second_interviewer = models.CharField(max_length=135, blank=True, verbose_name='面试官') second_interviewer_user = models.ForeignKey(User,related_name='second_interviewer_user',on_delete=models.CASCADE,blank=True, verbose_name=_('二面面试官'),null=True) # HR hr_score = models.DecimalField(max_digits=3, decimal_places=1, blank=True, verbose_name='hr复试得分',null=True,help_text=_('1~5分')) hr_result = models.CharField(choices=HR_SCORE, blank=True, verbose_name='HR结果', max_length=135) # hr_interviewer = models.CharField(max_length=135, blank=True, verbose_name='面试官') hr_interviewer_user = models.ForeignKey(User,related_name='hr_interviewer_user',on_delete=models.CASCADE,blank=True, verbose_name=_('HR'),null=True) ···
然后执行数据迁移操作
运行服务器
4)设置面试官只读权限
在admin.py
设置如下
······ # empty_value_display = "空" # 没有数据时的显示 默认为 - # readonly_fields = ('first_interviewer_user',) # in_list_page non-editable and readonly def get_group_name(self, user): group_name = [] for g in user.groups.all(): # 循环groups对象列表 group_name.append(g.name) # 附加对象的名字 return group_name # # # 设置面试官只读权限 def get_readonly_fields(self, request, obj=None): # 根据用户得到 该用户所在群组 group_name = self.get_group_name(request.user) # 如果其为面试官,则返回只读字段 if 'interviewer' in group_name: logger.info("interview is in the user'group for %s" % request.user.username) return ('first_interviewer_user', 'second_interviewer_user') # 返回值必须是可迭代对象 return ('',) # 返回值必须是可迭代对象 , 不能返回空
面试官只读
5) 设置面试官可直接在列表修改面试官
目前django没有对应的方法get_list_editable
,我们需要重写父类方法
def get_group_name(self, user): group_name = [] for g in user.groups.all(): # 循环groups对象列表 group_name.append(g.name) # 附加对象的名字 return group_name # 目前django没有对应的方法 def get_list_editable(self, request): groups_name = self.get_group_name(request.user) if request.user.is_superuser or 'hr' in groups_name: return ('first_interviewer_user', 'second_interviewer_user',) return () # 可直接在页面修改的数据 # 我们需要重写父类方法 def get_changelist_instance(self, request): """ override admin method and list_editable property value with values returned by our custom method implementation. """ self.list_editable = self.get_list_editable(request) # self 参数在前面的 self.get 就已经指明了 return super(CandidateAdmin, self).get_changelist_instance(request)
- 面试官
- 超级管理员或者hr
二、样式美化
1) 美化admin后台
pip install django-grappelli
- 安装后在
setting.py
进行配置
在添加主题应用时,是需要在其他应用前面的
INSTALLED_APPS = [ 'grappelli', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'jobs', 'interview', ······
- 在项目
urls.py
引入grappelli
路由
······· path('grappelli/', include('grappelli.urls')), ) ·······
- 效果:
这里的'classes': ('collapse',),
分栏隐藏效果失效了
# 定义集合的字段列表 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", "first_interviewer_user", ), 'classes': ('collapse',), "description": '请由面试官输入该信息'}), ('第二轮面试', {'fields': ("second_score", "second_result", "second_interviewer_user", ), 'classes': ('collapse',), "description": '请由面试官输入该信息'}), ('第三轮面试', {'fields': ("hr_score", "hr_result", "hr_interviewer_user", ), 'classes': ('collapse',), "description": '请由面试官输入该信息'}) )
2)美化页面
- 安装三板斧
- 安装
bootstrap
等使用见 - 官方文档bootstrap3 or bootstrap4 - 安装
tailwind
模块,详情见参考文献,这里踩了个大坑!建议直接引入css链接,简单粗暴,安装tialwind
模块需要安装导入,初始化,配置模板标签一堆功夫,出了一点错花费时间更多,且出现和现有版本不兼容情况,所以直接引入链接就好了,简单粗暴! - 安装
django-widget-tweaks
,自定义css样式,配置见参考文献
在tailwind网站找模板下载,自定义配置样式嵌套 ( 注意表单加自定义css需要用到
widget-tweaks
)
模板地址:https://www.tailwindtoolbox.com/starter-templates
tailwind中文官方文档:https://www.tailwindcss.cn/docs/responsive-design
login.html
页面代码,signup.html
也是一样的思路
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>login</title> <!-- Tailwind --> <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"> <link href="https://cdn.bootcdn.net/ajax/libs/font-awesome/5.13.0/css/all.min.css" rel="stylesheet"> <style> @import url('https://fonts.googleapis.com/css?family=Karla:400,700&display=swap'); .font-family-karla { font-family: karla; } .forgetpassword{ text-decoration: underline; } </style> </head> <body class="bg-white font-family-karla h-screen"> {% load i18n %} {% load account socialaccount %} {% load widget_tweaks %} {% get_providers as socialaccount_providers %} <div class="w-full flex flex-wrap"> <!-- Login Section --> <div class="w-full md:w-1/2 flex flex-col"> <div class="flex justify-center md:justify-start pt-12 md:pl-12 md:-mb-24"> <a href="#" class="bg-black text-white font-bold text-xl p-4">{% trans "recruitment" %}</a> </div> <div class="flex flex-col justify-center md:justify-start my-auto pt-8 md:pt-0 px-8 md:px-24 lg:px-32"> <p class="text-center text-3xl">{% trans "Welcome." %}</p> <form class="flex flex-col pt-3 md:pt-8" method="POST" action="{% url 'account_login' %}" > {% csrf_token %} <div class="flex flex-col pt-4"> <label for="login" class="text-lg">{% trans "Login" %}</label> {% render_field form.login class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mt-1 leading-tight focus:outline-none focus:shadow-outline" placeholder=form.login.label id="login" %} <!-- <input type="email" id="account" placeholder="your@email.com or username" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mt-1 leading-tight focus:outline-none focus:shadow-outline"> --> </div> <div class="flex flex-col pt-4"> <label for="Password" class="text-lg">Password</label> {% render_field form.password class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mt-1 leading-tight focus:outline-none focus:shadow-outline" placeholder=form.password.label id="Password" %} <!-- <input type="email" id="account" placeholder="your@email.com or username" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mt-1 leading-tight focus:outline-none focus:shadow-outline"> --> </div> {{ form.errors.as_text|cut:"__all__"|cut:"*" }} <!-- <div class="flex flex-col pt-4"> <label for="password" class="text-lg">Password</label> <input type="password" id="password" placeholder="Password" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mt-1 leading-tight focus:outline-none focus:shadow-outline"> </div> --> {% if redirect_field_value %} <input type="hidden" name="{{ redirect_field_name }}" value="{{ redirect_field_value }}"/> {% endif %} <br> <a class="forgetpassword" href="{% url 'account_reset_password' %}">{% trans "Forgot Password? " %}</a> <button class="bg-black text-white font-bold text-lg hover:bg-gray-700 p-2 mt-8" type="submit">{% trans "Log In" %} </button> </form> <div class="text-center pt-12 pb-12"> <p>{% trans "Don't have an account?" %} <a href="{{ signup_url }}" class="underline font-semibold">{% trans "Register here." %} </a></p> </div> </div> </div> <!-- Image Section --> <div class="w-1/2 shadow-2xl"> <img class="object-cover w-full h-screen hidden md:block" src="/static/account/images/photo-1555679427-1f6dfcce943b.jfif"> </div> </div> </body> </html>
- 效果:
- 值得注意一点是:修改
base.html
模板一定要注意再注意 (不然后面样式会像麻花一样乱)
参考文献
🤞到这里,如果还有什么疑问🤞 🎩欢迎私信博主问题哦,博主会尽自己能力为你解答疑惑的!🎩 🥳如果对你有帮助,你的赞是对博主最大的支持!!🥳