30 | 遗留系统集成:为已有系统数据库生成管理后台
流程说明:为已有数据库生成管理后台
![在这里插入图片描述](https://img-blog.csdnimg.cn/7534affb9f0b47639b6757c068ebf636.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
创建项目和应用
django-admin startproject empmanager
django-admin startapp candidates
编辑settings.py的数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
生成model类
python manage.py inspectdb
python manage.py inspectdb>candidates/models.py
调整model和注册到admin
- 调整model
删掉auth相关的model。
外键应用的models要新增related_name。
from django.db import models
from django.contrib.auth.models import User
class Candidate(models.Model):
userid = models.IntegerField(unique=True, blank=True, null=True)
username = models.CharField(max_length=135)
city = models.CharField(max_length=135)
phone = models.CharField(max_length=135)
email = models.CharField(max_length=135)
apply_position = models.CharField(max_length=135)
born_address = models.CharField(max_length=135)
gender = models.CharField(max_length=135)
candidate_remark = models.CharField(max_length=135)
bachelor_school = models.CharField(max_length=135)
master_school = models.CharField(max_length=135)
doctor_school = models.CharField(max_length=135)
major = models.CharField(max_length=135)
degree = models.CharField(max_length=135)
test_score_of_general_ability = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
paper_score = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
first_score = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
first_learning_ability = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
first_professional_competency = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
first_advantage = models.TextField()
first_disadvantage = models.TextField()
first_result = models.CharField(max_length=256)
first_recommend_position = models.CharField(max_length=256)
first_remark = models.CharField(max_length=135)
second_score = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
second_learning_ability = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
second_professional_competency = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
second_pursue_of_excellence = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
second_communication_ability = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
second_pressure_score = models.DecimalField(max_digits=10, decimal_places=5, blank=True, null=True) # max_digits and decimal_places have been guessed, as this database handles decimal fields as float
second_advantage = models.TextField()
second_disadvantage = models.TextField()
second_result = models.CharField(max_length=256)
second_recommend_position = models.CharField(max_length=256)
second_remark = models.CharField(max_length=135)
hr_score = models.CharField(max_length=10)
hr_responsibility = models.CharField(max_length=10)
hr_communication_ability = models.CharField(max_length=10)
hr_logic_ability = models.CharField(max_length=10)
hr_potential = models.CharField(max_length=10)
hr_stability = models.CharField(max_length=10)
hr_advantage = models.TextField()
hr_disadvantage = models.TextField()
hr_result = models.CharField(max_length=256)
hr_remark = models.CharField(max_length=256)
creator = models.CharField(max_length=256)
created_date = models.DateTimeField()
modified_date = models.DateTimeField(blank=True, null=True)
last_editor = models.CharField(max_length=256)
first_interviewer_user = models.ForeignKey(User, models.DO_NOTHING, related_name='first_interviewer_user',blank=True, null=True)
hr_interviewer_user = models.ForeignKey(User, models.DO_NOTHING, related_name='hr_interviewer_user',blank=True, null=True)
second_interviewer_user = models.ForeignKey(User, models.DO_NOTHING, related_name='second_interviewer_user',blank=True, null=True)
class Meta:
managed = False
db_table = 'candidate'
class JobsJob(models.Model):
job_type = models.SmallIntegerField()
job_name = models.CharField(max_length=250)
job_city = models.SmallIntegerField()
job_responsibility = models.TextField()
job_requirement = models.TextField()
created_date = models.DateTimeField()
modified_date = models.DateTimeField()
creator = models.ForeignKey(User, models.DO_NOTHING, blank=True, null=True)
class Meta:
managed = False
db_table = 'jobs_job'
class JobsResume(models.Model):
username = models.CharField(max_length=135)
city = models.CharField(max_length=135)
phone = models.CharField(max_length=135)
email = models.CharField(max_length=135)
apply_position = models.CharField(max_length=135)
born_address = models.CharField(max_length=135)
gender = models.CharField(max_length=135)
picture = models.CharField(max_length=100)
attachment = models.CharField(max_length=100)
bachelor_school = models.CharField(max_length=135)
master_school = models.CharField(max_length=135)
doctor_school = models.CharField(max_length=135)
major = models.CharField(max_length=135)
degree = models.CharField(max_length=135)
created_date = models.DateTimeField()
modified_date = models.DateTimeField()
candidate_introduction = models.TextField()
work_experience = models.TextField()
project_experience = models.TextField()
applicant = models.ForeignKey(User, models.DO_NOTHING, blank=True, null=True)
class Meta:
managed = False
db_table = 'jobs_resume'
from django.contrib import admin
# Register your models here.
from .models import JobsJob,JobsResume,Candidate
admin.site.register(JobsJob)
admin.site.register(JobsResume)
admin.site.register(Candidate)
admin管理后台页面
![在这里插入图片描述](https://img-blog.csdnimg.cn/11df04bcb1cc424f90e89d1414445803.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/56bae19360e54ad78a36da110b94404b.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
31 | Django的中间件(Middleware)
中间件说明
![在这里插入图片描述](https://img-blog.csdnimg.cn/47d15048a72641bcb78d75a66a059f18.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
32 | 创建请求日志、性能日志记录中间件
创建中间件的流程说明
![在这里插入图片描述](https://img-blog.csdnimg.cn/2533dd883efb4d279dd889b69d692169.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
定义实现中间件
import time
import logging
logger = logging.getLogger(__name__)
def performance_logger_middleware(get_response):
def middleware(request):
start_time = time.time()
response = get_response(request)
duration = time.time() - start_time
response["X-Page-Duration-ms"] = int(duration * 1000)
logger.info("%s %s %s", duration, request.path, request.GET.dict() )
return response
return middleware
注册middleware到settings中
MIDDLEWARE = [
'interview.performance.performance_logger_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',
]
配置日志文件路径
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,
},
},
}
效果呈现
-
文件
![在这里插入图片描述](https://img-blog.csdnimg.cn/ada32e0bdcb647e1aee854b9ced291c8.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
-
终端
![在这里插入图片描述](https://img-blog.csdnimg.cn/9706842ebcb14cecb91d9b994cddbab3.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
33 | 在Django中支持多语言
流程说明:使用多语言
![在这里插入图片描述](https://img-blog.csdnimg.cn/41900a1ee03e4e3687db0ff626d54b34.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
![在这里插入图片描述](https://img-blog.csdnimg.cn/5afdb4fd2a094f7a81af2da86b15b5af.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_16,color_FFFFFF,t_70,g_se,x_16)
jobs/models.py使用多语言
from django.utils.translation import gettext_lazy as _
from django.db import models
from django.contrib.auth.models import User
from datetime import datetime
from django.utils.translation import gettext_lazy as _
# Create your models here.
# 候选人学历
DEGREE_TYPE = ((u'本科', u'本科'), (u'硕士', u'硕士'), (u'博士', u'博士'))
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
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
jobs/template/models.py使用多语言
使用{% translate “匠果科技开放职位” %}和{% blocktranslate with user_name=user.username %}
<!--jobs/templates/base.html-->
<!--bootstrap start-->
{# 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 %}
<!--bootstrap end-->
<h1 style="margin:auto;width:50%">{% translate "匠果科技开放职位" %}</h1>
<p></p>
{% block header %}
<a href="/" style="text-decoration: none; color:#007bff">{% translate "Homepage" %}</a>
<a href="/joblist" style="text-decoration: none; color:#007bff">{% translate job_list" %}</a>
{% if user.is_authenticated %}
<a href="/accounts/logout" style="text-decoration: none; color:#007bff">{% translate Logout" %}</a>
{% else %}
<a href="/accounts/login" style="text-decoration: none; color:#007bff">{% translate Login" %}</a>
{% endif %}
{% if user.is_authenticated %}
<p>{% blocktranslate with user_name=user.username %} 终于等到你 {{ user_name }}, 期待加入我们,用技术去探索一个新世界{% endblocktranslate %}</p>
{% else %}
<br>{% translate "欢迎你,期待加入我们,登陆后可以提交简历."%}<br>
{% endif %}
{% endblock %}
{% block content %}
{% endblock %}
生成文本格式的多语言资源文件(.po)
mkdir locale
django-admin makemessages -l zh_HANS -l en
![在这里插入图片描述](https://img-blog.csdnimg.cn/9751bad28a1448a2a9d2b66c4dd21bd6.png)
- locale\en\LC_MESSAGES\django.po
msgstr为翻译结果,需要我们自己在翻译成英文(我天真以为可以自动翻译)。
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-12-02 06:55+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#. Translators: 职位实体的翻译
#: .\jobs\models.py:29
msgid "职位类别"
msgstr "Position category"
#: .\jobs\models.py:30
msgid "职位名称"
msgstr "Job title"
#: .\jobs\models.py:31
msgid "工作地点"
msgstr "working place"
#: .\jobs\models.py:32
msgid "职位职责"
msgstr "responsibilities"
#: .\jobs\models.py:33
msgid "职位要求"
msgstr "Job Requirements"
#: .\jobs\models.py:34
msgid "创建人"
msgstr "Creator"
#: .\jobs\models.py:35
msgid "Creation date"
msgstr ""
#: .\jobs\models.py:36
msgid "modification date"
msgstr ""
#: .\jobs\models.py:39
msgid "职位"
msgstr "position"
#: .\jobs\models.py:40
msgid "职位列表"
msgstr "Position list"
#. Translators: 简历实体的翻译
#: .\jobs\models.py:50
msgid "姓名"
msgstr "full name"
#: .\jobs\models.py:51
msgid "申请人"
msgstr "applicant"
#: .\jobs\models.py:52
msgid "城市"
msgstr "city"
#: .\jobs\models.py:53
msgid "手机号码"
msgstr "phone number"
#: .\jobs\models.py:54
msgid "邮箱"
msgstr "mailbox"
#: .\jobs\models.py:55
msgid "应聘职位"
msgstr "Position Applied"
#: .\jobs\models.py:56
msgid "生源地"
msgstr "Place of origin"
#: .\jobs\models.py:57
msgid "性别"
msgstr "Gender"
#: .\jobs\models.py:58
msgid "个人照片"
msgstr "Personal photos"
#: .\jobs\models.py:59
msgid "简历附件"
msgstr "Resume attachment"
#: .\jobs\models.py:62
msgid "本科学校"
msgstr "Undergraduate school"
#: .\jobs\models.py:63
msgid "研究生学校"
msgstr "post-graduate schools"
#: .\jobs\models.py:65
msgid "专业"
msgstr "major"
#: .\jobs\models.py:66
msgid "学历"
msgstr "education"
#: .\jobs\models.py:76
msgid "简历"
msgstr "resume"
#: .\jobs\models.py:77
msgid "简历列表"
msgstr "Resume list"
#: .\jobs\templates\base.html:18
msgid "匠果科技开放职位"
msgstr "Open position of Jianguo Technology"
#: .\jobs\templates\base.html:23
msgid "Homepage"
msgstr ""
#: .\jobs\templates\base.html:24
msgid "job_list"
msgstr ""
#: .\jobs\templates\base.html:26
msgid "Logout"
msgstr ""
#: .\jobs\templates\base.html:28
msgid "Login"
msgstr ""
#: .\jobs\templates\base.html:31
#, python-format
msgid " 终于等到你 %(user_name)s, 期待加入我们,用技术去探索一个新世界"
msgstr "Finally, you %(user_name)s are looking forward to joining us and exploring a new world with technology"
#: .\jobs\templates\base.html:33
msgid "欢迎你,期待加入我们,登陆后可以提交简历."
msgstr "Welcome and look forward to joining us. You can submit your resume after logging in."
#: .\jobs\templates\base.html:51
msgid "Switch"
msgstr ""
#: .\recruitment\urls.py:30
msgid "招聘管理系统"
msgstr "Recruitment management system"
#: .\settings\base.py:115
msgid "Chinese"
msgstr ""
#: .\settings\base.py:116
msgid "English"
msgstr ""
编译生成可以高效使用的二进制文件(.mo)
django-admin compilemessages
![在这里插入图片描述](https://img-blog.csdnimg.cn/d9a5ba839e5943d590cb4506993b869e.png)
settings添加多语言配置
MIDDLEWARE = [
...
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',### 多语言中间件
'django.middleware.common.CommonMiddleware',
...
]
# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGES = [
('zh-hans', _('Chinese')),
('en', _('English')),
]
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = True
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'locale'),
)
选择语言的功能
<div style="flex: 1; align-content:right;">
<form action="{% url 'set_language' %}" method="post" style="margin-block-end: 0em;">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}">
<select name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value={% translate "Switch" %} style="font-size:12;height:20px">
</form>
</div>
</div>
<hr style="margin-top: 0px; ">
recruitment/urls.py
path('i18n/', include('django.conf.urls.i18n')),
多语言效果
![在这里插入图片描述](https://img-blog.csdnimg.cn/87d56b8ef300424bb17fa862894adf94.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
坑:CommandError: Can’t find msguniq. Make sure you have GNU gettext tools 0.15 or newer installed.
参考文章https://blog.csdn.net/weixin_30836759/article/details/99920251
34 | 错误和异常日志上报:Sentry集成(待研究)
教材
![在这里插入图片描述](https://img-blog.csdnimg.cn/f5128b6fcb5741f7b39b883a01905826.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/3bbd87eb63224b81a29d751fbcc0f7c2.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/e2bfa687047d4531a6651471faabc964.png)
参考文档
https://blog.csdn.net/yangjianrong1985/article/details/106913358
下载链接
https://gitee.com/fqzhang/onpremise
环境需要linux或WSL,否则无法执行
![在这里插入图片描述](https://img-blog.csdnimg.cn/b9f40a17d3fd41ddb925dc7575f3ef13.png)
35 | 错误和异常日志上报:捕获异常上报到Sentry并发送钉钉群通知(待研究)
![在这里插入图片描述](https://img-blog.csdnimg.cn/3d973711c1c44541a339e98a11bc82d5.png)
performance.py
class PerformanceAndExceptionLoggerMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
start_time = time.time()
response = self.get_response(request)
duration = time.time() - start_time
response["X-Page-Duration-ms"] = int(duration * 1000)
logger.info("duration:%s url:%s parameters:%s", duration, request.path, request.GET.dict() )
# Code to be executed for each request/response after
# the view is called.
return response
def process_exception(self, request, exception):
if exception:
message = "url:{url} ** msg:{error} ````{tb}````".format(
url = request.build_absolute_uri(),
error = repr(exception),
tb = traceback.format_exc()
)
logger.warning(message)
# send dingtalk message
dingtalk.send(message)
# capture exception to sentry:
capture_exception(exception)
return HttpResponse("Error processing the request, please contact the system administrator.", status=500)
36 | Django安全防护:防止XSS跨站脚本攻击
![在这里插入图片描述](https://img-blog.csdnimg.cn/9c8574ae7f7c465f9f58477ec7b9fd62.jpg?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
简单来说,使用render就可以避免XSS跨站JS脚本攻击。
37 | Django安全防护:CSRF跨站请求伪造和SQL注入攻击
![在这里插入图片描述](https://img-blog.csdnimg.cn/db80d1cf51b64e27b0956241f57bb0cc.jpg?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
简单来说,template使用CSRF令牌避免CSRF跨站请求伪造,数据查询不要在使用原始SQL查询时还使用参数就可以避免SQL注入攻击(使用ORM查询数据最安全)。
38 | Django Rest Framework开放API
https://www.django-rest-framework.org/
Installation安装
pip install djangorestframework
pip install markdown # Markdown support for the browsable API.
pip install django-filter # Filtering support
settings/base.py:Add ‘rest_framework’ to your INSTALLED_APPS setting.
INSTALLED_APPS = [
...
'rest_framework',
]
settings/base.py:增加REST_FRAMEWORK
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'
]
}
your root urls.py file
from django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets
from jobs.models import Job
#### rest_framework
# Serializers define the API representation.
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['url', 'username', 'email', 'is_staff']
# ViewSets define the view behavior.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
class JobSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Job
fields = '__all__'
class JobViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Job.objects.all()
serializer_class = JobSerializer
# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
router.register(r'jobs', JobViewSet)
urlpatterns = [
...
# django rest api & api auth (login/logout)
path('api/', include(router.urls)),
path('api-auth/', include('rest_framework.urls')),
]
启动应用
![在这里插入图片描述](https://img-blog.csdnimg.cn/df3c20ad5e6843b5a183ab8f3cb12481.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
39 | 在Django中使用缓存&Redis的使用
https://django-redis-chs.readthedocs.io/zh_CN/latest/
下载和安装redis
链接
定位到redis解压缩后的文件夹中, 打开命令提示符对话框输入"cmd"。然后在命令窗口输入“redis-server.exe redis.windows.conf”出现如下界面即成功启动。
![在这里插入图片描述](https://img-blog.csdnimg.cn/ca29deee84b64a06a4aeaea080a3aa1f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
启动redis服务
双击redis-server.exe可启动redis服务
安装pip install -i https://pypi.tuna.tsinghua.edu.cn/simple django_redis
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple django_redis
启用中间件
MIDDLEWARE = [
'interview.performance.performance_logger_middleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.cache.UpdateCacheMiddleware',#redis中间件
'django.middleware.common.CommonMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',#redis中间件
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
建立CACHES
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
#"PASSWORD":"mysecret",
"SOCKET_CONNECT_TIMEOUT": 5, # in seconds
"SOCKET_TIMEOUT": 5, # r/w timeout in seconds
}
}
}
缓存效果
![在这里插入图片描述](https://img-blog.csdnimg.cn/98361aa14e414db3a258ab6b2d36287c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_19,color_FFFFFF,t_70,g_se,x_16)
目前bug
1.默认缓存10分钟,我还不知道在哪改。
2.目前换用户登录后,后一个用户可以访问到前一个用户的访问信息。需要redis清空缓存,请见下方做法。
https://blog.csdn.net/lthahaha/article/details/118926226
![在这里插入图片描述](https://img-blog.csdnimg.cn/134fc5da7dae4e6d9e8fd5ae339f0257.png)
40 | Django与Celery 集成:Celery的使用
celery文档
中文非官方文档
Installation & Bundles
![在这里插入图片描述](https://img-blog.csdnimg.cn/836fcb18f7df4bee9022200fd25e4dfa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
task.py脚本 & run_task.py脚本
run_task.py脚本是用来运行task.py脚本。
- recruitment\celery\task.py
#!coding=utf-8
from celery import Celery
# 第一个参数 是当前脚本的名称,第二个参数 是 broker 服务地址
app = Celery('tasks', backend='redis://127.0.0.1', broker='redis://127.0.0.1')
@app.task
def add(x, y):
return x + y
- recruitment\celery\run_task.py
#coding=utf-8
from tasks import add
result = add.delay(4, 4)
print('Is task ready: %s' % result.ready())
run_result = result.get(timeout=1)
print('task result: %s' % run_result)
CMD启动Celery服务
- 方法一:直接启动。win10上运行celery4.x就会出现bug,Celery ValueError: not enough values to unpack (expected 3, got 0)。
C:\Users\Season\Desktop\4.python网页前后端\Django基础教程\workspace4-recruiting\recruitment【40】Django与Celery 集成:Celery的使用\recruitment\celery>celery -A tasks worker --loglevel=INFO
C:\Users\Season\Desktop\4.python网页前后端\Django基础教程\workspace4-recruiting\recruitment【40】Django与Celery 集成:Celery的使用\recruitment\celery>python run_task.py
![在这里插入图片描述](https://img-blog.csdnimg.cn/2d4b7734950e40ddb700f4ee6c1a81d0.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
- 方法二:pip install eventlet,加入参数-P eventlet再启动。debug成功。
C:\Users\Season\Desktop\4.python网页前后端\Django基础教程\workspace4-recruiting\recruitment【40】Django与Celery 集成:Celery的使用\recruitment\celery>celery -A tasks worker --loglevel=INFO -P eventlet
C:\Users\Season\Desktop\4.python网页前后端\Django基础教程\workspace4-recruiting\recruitment【40】Django与Celery 集成:Celery的使用\recruitment\celery>python run_task.py
![在这里插入图片描述](https://img-blog.csdnimg.cn/8f108f09afe94b0f80197ea550404920.png)
Celery ValueError: not enough values to unpack (expected 3, got 0)的解决方案
https://blog.csdn.net/qq_30242609/article/details/79047660
启动flower
参考链接
Celery提供了一个工具flower,将各个任务的执行情况、各个worker的健康状态进行监控并以可视化的方式展现。
1.安装flower:
pip install flower
2.启动flower
例如启动项目工程下面celery_tasks目录的main.py 异步任务启动函数
flower -A celery_tasks.main --port=5555
我的启动如下
celery -A tasks flower --broker=redis://localhost:6379/0
![在这里插入图片描述](https://img-blog.csdnimg.cn/acba5e7f631c41a1a1eb0996fff81fad.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
3.进入http://localhost:5555即可查看。
![在这里插入图片描述](https://img-blog.csdnimg.cn/92bfadf05590450196f883bf8e32a5ee.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
4.可以查看发送的任务详情信息
![在这里插入图片描述](https://img-blog.csdnimg.cn/55433b8eb4a8443fbe3e0b6affd14d21.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
41 | Django与Celery集成:异步任务
https://docs.celeryproject.org/en/master/django/first-steps-with-django.html#using-celery-with-django
配置celery:recruitment\celery.py
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'settings.base')
app = Celery('recruitment')
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object('django.conf:settings', namespace='CELERY')
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
初始化:recruitment_init_.py
from __future__ import absolute_import, unicode_literals
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
__all__ = ('celery_app',)
celery配置放在settings/local.py
CELERY_BROKER_URL = 'redis://redis:6379/0'
CELERY_RESULT_BACKEND = 'redis://redis:6379/1'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_RESULT_SERIALIZER = 'json'
CELERY_TASK_SERIALIZER = 'json'
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERYD_MAX_TASKS_PER_CHILD = 10
CELERYD_LOG_FILE = os.path.join(BASE_DIR, "logs", "celery_work.log")
CELERYBEAT_LOG_FILE = os.path.join(BASE_DIR, "logs", "celery_beat.log")
发布消息的应用改为异步
from __future__ import absolute_import, unicode_literals
from celery import shared_task
from .dingtalk import send
@shared_task
def send_dingtalk_message(message):
send(message)
from .tasks import send_dingtalk_message
# 通知一面面试官面试
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, '已经成功发送面试通知')
启动服务
celery -A proj worker -l INFO
- flower监控服务
- django服务(常规操作)
总结Django与Celery集成:异步任务
![在这里插入图片描述](https://img-blog.csdnimg.cn/b1128a6876af4db5b6d30b0407723afe.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAaSBzZWUgdGhlIGZ1dHVyZQ==,size_20,color_FFFFFF,t_70,g_se,x_16)
42 | Django与Celery集成:定时任务
我的项目https://blog.csdn.net/m0_46629123/article/details/126495062
安装beat
pip install django-celery-beat
加入APP列表
INSTALLED_APPS = [
'simpleui',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'GAGA_meeting',
'django_celery_beat',
]
![在这里插入图片描述](https://img-blog.csdnimg.cn/8a8a5abcd8d34665b92fd0c24c3fa822.png)
数据库迁移
python manage.py makemigrations
python manage.py migrate
![在这里插入图片描述](https://img-blog.csdnimg.cn/f55376c0ea2b4e16ba840868dbcdb4e7.png)
intervals填写周期
![在这里插入图片描述](https://img-blog.csdnimg.cn/bc6cf6063fb447e79f193c6e483ab78f.png)
crontab填写周期
![在这里插入图片描述](https://img-blog.csdnimg.cn/18301ef0de564d87994675512a3c26f3.png)
periodic tasks填写定期任务
![在这里插入图片描述](https://img-blog.csdnimg.cn/d91b2cb622af46558a1bd8e0537ee3e2.png)
手动启动beat:
celery -A GAGA beat --scheduler django_celery_beat.schedulers:DatabaseScheduler
![在这里插入图片描述](https://img-blog.csdnimg.cn/d4ad2456f2e14c9cad0c831ff58cd99a.png)
我的成功经验:
https://blog.csdn.net/m0_46629123/article/details/126495062
43 | 文件和图片上传功能
讲义
![在这里插入图片描述](https://img-blog.csdnimg.cn/db42ae3b998f4d27942a9a5e5bec613a.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/eadef5c33e424bbab2c501c3667ceb17.png)
settings.py设定media路径
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
根目录urls.py设定访问路径
![在这里插入图片描述](https://img-blog.csdnimg.cn/cbc54983483a4d86b7f5eb9d3039116f.png)
我的例子
## 媒体文件夹路由:读取"/static/"的数据
re_path('media/(?P<path>.*)', serve, {'document_root':settings.MEDIA_ROOT},name='media'),
model.py设定上传upload
picture = models.ImageField(upload_to='images/', blank=True, verbose_name=_('个人照片'))
attachment = models.FileField(upload_to='file/', blank=True, verbose_name=_('简历附件'))
class reward(models.Model):
# 奖品
id = models.AutoField(primary_key=True)
reward_name = models.CharField(max_length=135, blank=True, null=True, verbose_name=u'奖品名称')
reward_image = models.ImageField(max_length=135, blank=True, null=True, verbose_name=u'奖品照片',upload_to='static\images')
reward_score = models.IntegerField(blank=True, null=True,verbose_name=u'奖品积分')
reward_inventory_total = models.IntegerField(blank=True, null=True, verbose_name=u'奖品入库总量')
reward_inventory_used = models.IntegerField(blank=True, null=True, verbose_name=u'奖品使用量')
reward_inventory_left = models.IntegerField(blank=True, null=True, verbose_name=u'奖品剩余量')
class Meta:
db_table = u'reward'
verbose_name = u'奖品'
verbose_name_plural = u'奖品'
def __str__(self):
return self.reward_name
## 列表页显示图片
def image_img(self):
if not self.reward_image:
return '无'
return format_html(
"""<div><img src='{}' style='width:50px;height:50px;' ></div>""",
self.reward_image.url)
image_img.short_description = '图片'
admin.py显示上传的图片
## 列表页显示图片
def image_img(self):
if not self.reward_image:
return '无'
return format_html(
"""<div><img src='{}' style='width:50px;height:50px;' ></div>""",
self.reward_image.url)
image_img.short_description = '图片'
OSS存储(略)
![在这里插入图片描述](https://img-blog.csdnimg.cn/92e9a055e3ad46f6890823307ec74058.png)
44 | 实践中的问题:多数据库路由
教程
![在这里插入图片描述](https://img-blog.csdnimg.cn/748931a91ac34fd6a81b36a55dc62c2e.png)
settings.py配置多个数据库
![在这里插入图片描述](https://img-blog.csdnimg.cn/f268cb96d26447b3830943cd8b57c219.png)
inspect db命令
# 生成全部表
python manage.py inspectdb --database==running
# 生成指定表
python manage.py inspectdb --database==running area city >models.py
running应用(可选)
INSTALLED_APPS = [
...
'running',
...
]
注册到admin
from django.contrib import admin
# Register your models here.
from .models import JobsJob,JobsResume,Candidate
admin.site.register(JobsJob)
admin.site.register(JobsResume)
admin.site.register(Candidate)
添加路由
DATABASE_ROUTERS = ['settings.router.DatabaseRouter']
- settings/router.py来判断使用default数据库还是running数据库。
# settings/router.py
# database router to multiple database by app label
class DatabaseRouter:
route_app_labels = {'running'}
def db_for_read(self, model, **hints):
if model._meta.app_label in self.route_app_labels:
return 'running'
return 'default'
def db_for_write(self, model, **hints):
if model._meta.app_label in self.route_app_labels:
return 'running'
return 'default'
def allow_relation(self, obj1, obj2, **hints):
return None
def allow_migrate(self, db, app_label, model_name=None, **hints):
"""
遗留数据库中的表不允许迁移
"""
if app_label in self.route_app_labels:
return False
return True
45 | Django之美:3 行代码支持大数据量的关联外键
场景
![在这里插入图片描述](https://img-blog.csdnimg.cn/e0366ffa2cf64d519776aca6a21c8448.png)
自动模糊查询
- models.py
class City(models.Model):
cityid = models.AutoField(primary_key=True)
countryid = models.ForeignKey(Country, db_column='countryid', null=True, on_delete=models.SET_NULL)
areaid = models.PositiveIntegerField(blank=True, null=True)
provinceid = models.ForeignKey(Province, db_column='provinceid', null=True, on_delete=models.SET_NULL)
chn_name = models.CharField(max_length=64)
eng_name = models.CharField(max_length=64, blank=True, null=True)
sort = models.PositiveIntegerField()
class Meta:
managed = False
db_table = 'city'
def __str__(self):
return self.chn_name if self.chn_name else self.eng_name if self.eng_name else ""
@admin.register(City)
class CityAdmin(ReadOnlyAdmin):
autocomplete_fields = ['provinceid','countryid',]
多级关联查询django-smart-selects
![在这里插入图片描述](https://img-blog.csdnimg.cn/c6b1874a39424e898470bc2cf39afd33.png)
46 | Django之美:20行代码实现只读站点ReadOnlyAdmin
场景
![在这里插入图片描述](https://img-blog.csdnimg.cn/944c62da5734401f9570c048e0fbeaef.png)
代码
class ReadOnlyAdmin(admin.ModelAdmin):
readonly_fields = []
def get_list_display(self, request):
return [field.name for field in self.model._meta.concrete_fields]
def get_readonly_fields(self, request, obj=None):
return list(self.readonly_fields) + \
[field.name for field in obj._meta.fields] + \
[field.name for field in obj._meta.many_to_many]
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False
def has_change_permission(self, request, obj=None):
return False
@admin.register(Country)
class CountryAdmin(ReadOnlyAdmin):
search_fields = ('chn_name', 'eng_name',)
效果:字段只读,方法禁用
![在这里插入图片描述](https://img-blog.csdnimg.cn/c4106fb026ef41c6b4f9a25f373e9c4a.png)
47| Django之美:10行代码自动注册所有Model到Admin管理后台(可选)
场景
![在这里插入图片描述](https://img-blog.csdnimg.cn/ac27327d1931409cb154d268c3b2de21.png)
- app/admins.py
- settings.py中将running调到APP最后
```python
INSTALLED_APPS = [
...
'running',]
更简单的方法
![在这里插入图片描述](https://img-blog.csdnimg.cn/6201e64d3bb14a6aaeda60a49c805504.png)
用sandman2来更更简单地自动定义模型(不能与uwsgi生产环境同时使用)
![在这里插入图片描述](https://img-blog.csdnimg.cn/1961ae84452242d1a0475501aaf80af7.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/1a7722f9fa7e48eb97bbe2ac9e9d037e.png)
48 | Django之美:Signals信号及其使用场景(待研究)
什么是Signals信号
![在这里插入图片描述](https://img-blog.csdnimg.cn/59b2e14ee2964cae9e7800d86c254aab.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/a9ff0834d3924810be12ac3c7bc0673e.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/dd6174f94c254b54ade14b53724c9dfd.png)
如何使用Signals信号
![在这里插入图片描述](https://img-blog.csdnimg.cn/2187d825bb574e8fa22aad6a192db575.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/ce0e54d9f24d4243a469a8d9a85c7bee.png)
自定义信号
![在这里插入图片描述](https://img-blog.csdnimg.cn/cdb2993c24f04de4b6e42aade6d493a3.png)
49 | Django之美:优雅的架构设计 - CSR架构总结之Celery
Celery 架构
![在这里插入图片描述](https://img-blog.csdnimg.cn/ea9df407657b4cb98c06c0d3bf04fedd.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/9489937cc9534ddd869e1a94dbfb36fe.png)
Celery 中的核心概念
![在这里插入图片描述](https://img-blog.csdnimg.cn/42d3787a7b7b4f8eaa049c014f880c1e.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/beff08b2d054443792cd5219e6611f90.png)
Celery 的跨平台 - 不同语言的客户端/服务器端实现
![在这里插入图片描述](https://img-blog.csdnimg.cn/1888ff3ca2a246b78a90a1fd9674d31c.png)
Celery 的高可用架构
![在这里插入图片描述](https://img-blog.csdnimg.cn/3609f732a7884def8a1bd8104f4b8be7.png)
50 | Django之美:优雅的架构设计 - CSR架构总结之Sentry&Django Framework
Sentry 架构之美
![在这里插入图片描述](https://img-blog.csdnimg.cn/036da6acf86945849b7e8fc0216ce3de.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/601e6323c7e340a781551844aa87ab1c.png)
Sentry 中的概念
![在这里插入图片描述](https://img-blog.csdnimg.cn/842bb8fbac7f4550a5760642e287131e.png)
Sentry 整体架构
![在这里插入图片描述](https://img-blog.csdnimg.cn/6aac5589b0c944268bb8c088bc19b4b2.png)
snuba的作用
![在这里插入图片描述](https://img-blog.csdnimg.cn/761d208715ed4bf2827c9a66cb5f9a83.png)
DRF 架构之美
![在这里插入图片描述](https://img-blog.csdnimg.cn/f2dbe9f681204b469260180d288cf067.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/3b76d022dd234f64a6a6ad6c0ddcff7b.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/5a7de0415083469a98eed3e9a7d8c522.png)
51 | Django之美:Django的常用插件
![在这里插入图片描述](https://img-blog.csdnimg.cn/8baec3c7b2c14016bc51e5d8d0032329.png)
Simple UI
![在这里插入图片描述](https://img-blog.csdnimg.cn/acb62216e47d4ec08a5eb290983749dd.png)
INSTALLED_APPS = [
'simpleui',
.....
]
Django Debug Toolbar
https://django-debug-toolbar.readthedocs.io/en/latest/installation.html
![在这里插入图片描述](https://img-blog.csdnimg.cn/83708b1ca16b4a96b60eb845ffaa672e.png)
settings.py设定
"""
Django settings for training_system 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 = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
BASE_DIR = Path(__file__).resolve().parent.parent
#BASE_DIR = Path(__file__).resolve()
print('BASE_DIR',BASE_DIR)
#print('BASE_DIR2',os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# 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-$z^45$dg5xl!3oo@ma54#n&9x-3p3_*6g^719c80xy*0dww7u='
# SECURITY WARNING: don't run with debug turned on in production!
#DEBUG = False
DEBUG = True
if DEBUG == True:
INTERNAL_IPS = ['127.0.0.1', ]
DEBUG_TOOLBAR_CONFIG = {
'JQUERY_URL': 'https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js',
'SHOW_COLLAPSED': True,
'SHOW_TOOLBAR_CALLBACK': lambda x: True,
}
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
'simpleui',
#'grappelli',
'bootstrap4',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'training',
'debug_toolbar',
]
MIDDLEWARE = [
'debug_toolbar.middleware.DebugToolbarMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
#'django.middleware.cache.UpdateCacheMiddleware',#redis中间件
'django.middleware.common.CommonMiddleware',
#'django.middleware.cache.FetchFromCacheMiddleware',#redis中间件
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'training_system.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'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 = 'training_system.wsgi.application'
# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases
print(Path(__file__).resolve().parent)
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
#'NAME': BASE_DIR / 'db.sqlite3',
'NAME': Path(__file__).resolve().parent /'SQL' /'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/
# 修改中文,Django内部设置zh_Hans方法指向中文
LANGUAGE_CODE = 'zh-hans'
# 修改中国时区
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
#USE_L10N = True
USE_L10N = False
DATETIME_FORMAT = 'Y-m-d H:i:s'
DATE_FORMAT = 'Y-m-d'
#USE_TZ = True
USE_TZ = False
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/
# 通过url直接访问我在项目中的静态文件
STATIC_URL = '/static/'
# 部署静态文件时(pyhtonmanage.pycollectstatic)所有的静态文静聚合的目录
STATIC_ROOT = os.path.join(BASE_DIR, "/static/")
# STATICFILES_DIRS告诉django,首先到STATICFILES_DIRS里面寻找静态文件,其次再到各个app的static文件夹里面找
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "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'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
LOGIN_URL = '/user_login/'
# CACHES = {
# "default": {
# "BACKEND": "django_redis.cache.RedisCache",
# "LOCATION": "redis://127.0.0.1:6379/1",
# "OPTIONS": {
# "CLIENT_CLASS": "django_redis.client.DefaultClient",
# "PASSWORD":"mysecret",
# "SOCKET_CONNECT_TIMEOUT": 5, # in seconds
# "SOCKET_TIMEOUT": 5, # r/w timeout in seconds
# }
# }
# }
Haystack
![在这里插入图片描述](https://img-blog.csdnimg.cn/8e14be6ae4c94071a27546c9721c93ec.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/0348ebda6cc444b5a84217eee8448ea7.png)
![在这里插入图片描述](https://img-blog.csdnimg.cn/4686018aea864b91b184a269834850ce.png)