【Django快速开发实战】(30~51)使用Django创建一个基础应用:职位管理系统

2023-11-06

30 | 遗留系统集成:为已有系统数据库生成管理后台

流程说明:为已有数据库生成管理后台

在这里插入图片描述

创建项目和应用

  • 创建新项目
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
  • 将数据库拷贝到models里面
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'
  • 注册到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)

admin管理后台页面

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

31 | Django的中间件(Middleware)

中间件说明

在这里插入图片描述

32 | 创建请求日志、性能日志记录中间件

创建中间件的流程说明

在这里插入图片描述

定义实现中间件

  • interview/performance.py
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中

  • settings\base.py
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',
]

配置日志文件路径

  • settings\base.py
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,
        },
    },
}

效果呈现

  • 文件
    在这里插入图片描述

  • 终端
    在这里插入图片描述

33 | 在Django中支持多语言

流程说明:使用多语言

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

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

在这里插入图片描述

  • 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

在这里插入图片描述

settings添加多语言配置

  • settings/base.py
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'),
)

选择语言的功能

  • jobs/template/base.html
<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')),

多语言效果

在这里插入图片描述

坑: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://blog.csdn.net/yangjianrong1985/article/details/106913358

下载链接

https://gitee.com/fqzhang/onpremise

环境需要linux或WSL,否则无法执行

在这里插入图片描述

35 | 错误和异常日志上报:捕获异常上报到Sentry并发送钉钉群通知(待研究)

在这里插入图片描述

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跨站脚本攻击

在这里插入图片描述

简单来说,使用render就可以避免XSS跨站JS脚本攻击。

37 | Django安全防护:CSRF跨站请求伪造和SQL注入攻击

在这里插入图片描述
简单来说,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')),
]

启动应用

在这里插入图片描述

39 | 在Django中使用缓存&Redis的使用

https://django-redis-chs.readthedocs.io/zh_CN/latest/

下载和安装redis

链接
定位到redis解压缩后的文件夹中, 打开命令提示符对话框输入"cmd"。然后在命令窗口输入“redis-server.exe redis.windows.conf”出现如下界面即成功启动。
在这里插入图片描述

启动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

启用中间件

  • settings\base.py
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

  • settings\base.py
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
        }
    }
}

缓存效果

在这里插入图片描述

目前bug

1.默认缓存10分钟,我还不知道在哪改。
2.目前换用户登录后,后一个用户可以访问到前一个用户的访问信息。需要redis清空缓存,请见下方做法。
https://blog.csdn.net/lthahaha/article/details/118926226
在这里插入图片描述

40 | Django与Celery 集成:Celery的使用

celery文档
中文非官方文档

Installation & Bundles

在这里插入图片描述

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

在这里插入图片描述

  • 方法二: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

在这里插入图片描述

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

在这里插入图片描述

3.进入http://localhost:5555即可查看。
在这里插入图片描述
4.可以查看发送的任务详情信息
在这里插入图片描述

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")

发布消息的应用改为异步

  • interview\tasks.py
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)
  • interview\admin.py
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, '已经成功发送面试通知')

启动服务

  • redis缓存服务(双击redis-server.exe)

  • celery异步服务(有bug未启动完成)

celery -A proj worker -l INFO
  • flower监控服务
  • django服务(常规操作)

总结Django与Celery集成:异步任务

在这里插入图片描述

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',
]

在这里插入图片描述

数据库迁移

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

intervals填写周期

在这里插入图片描述

crontab填写周期

在这里插入图片描述

periodic tasks填写定期任务

在这里插入图片描述

手动启动beat:

celery -A GAGA beat --scheduler django_celery_beat.schedulers:DatabaseScheduler

在这里插入图片描述

我的成功经验:

https://blog.csdn.net/m0_46629123/article/details/126495062

43 | 文件和图片上传功能

讲义

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

settings.py设定media路径

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

根目录urls.py设定访问路径

在这里插入图片描述
我的例子

    ## 媒体文件夹路由:读取"/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存储(略)

在这里插入图片描述

44 | 实践中的问题:多数据库路由

教程

在这里插入图片描述

settings.py配置多个数据库

在这里插入图片描述

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)

添加路由

  • settings.py
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 行代码支持大数据量的关联外键

场景

在这里插入图片描述

自动模糊查询

在这里插入图片描述- 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.py
@admin.register(City)
class CityAdmin(ReadOnlyAdmin):
    autocomplete_fields = ['provinceid','countryid',]

多级关联查询django-smart-selects

在这里插入图片描述

46 | Django之美:20行代码实现只读站点ReadOnlyAdmin

场景

在这里插入图片描述

代码

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',)

效果:字段只读,方法禁用

在这里插入图片描述

47| Django之美:10行代码自动注册所有Model到Admin管理后台(可选)

场景

在这里插入图片描述

  • app/admins.py
    在这里插入图片描述
  • settings.py中将running调到APP最后
```python
INSTALLED_APPS = [
...
    'running',]

更简单的方法

在这里插入图片描述

用sandman2来更更简单地自动定义模型(不能与uwsgi生产环境同时使用)

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

48 | Django之美:Signals信号及其使用场景(待研究)

什么是Signals信号

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

如何使用Signals信号

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

自定义信号

在这里插入图片描述

49 | Django之美:优雅的架构设计 - CSR架构总结之Celery

Celery 架构

在这里插入图片描述

在这里插入图片描述

Celery 中的核心概念

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

Celery 的跨平台 - 不同语言的客户端/服务器端实现

在这里插入图片描述

Celery 的高可用架构

在这里插入图片描述

50 | Django之美:优雅的架构设计 - CSR架构总结之Sentry&Django Framework

Sentry 架构之美

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

Sentry 中的概念

在这里插入图片描述

Sentry 整体架构

在这里插入图片描述

snuba的作用

在这里插入图片描述

DRF 架构之美

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

51 | Django之美:Django的常用插件

在这里插入图片描述

Simple UI

在这里插入图片描述

INSTALLED_APPS = [
    'simpleui',
.....
]

Django Debug Toolbar

https://django-debug-toolbar.readthedocs.io/en/latest/installation.html
在这里插入图片描述
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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Django快速开发实战】(30~51)使用Django创建一个基础应用:职位管理系统 的相关文章

随机推荐

  • 经典的Python爬虫和网络编程面试题

    1 动态加载又对及时性要求很高怎么处理 Selenium Phantomjs 尽量不使用 sleep 而使用 WebDriverWait 2 分布式爬虫主要解决什么问题 1 ip 2 带宽 3 cpu 4 io 3 什么是 URL URL
  • UG NX导出2D图纸

    创建图纸 1 同时按下ctrl shift D进入制图页面 点击左上角 新建图纸页 选择视图创建向导调整视图 2 方向 gt 定制的视图 然后指定一个面 点击 完成 导出2D图纸 文件 gt 导出AutoCAD DXF DWG 退出制图 同
  • 【Leetcode041】 最大子数组和

    53 最大子数组和 给你一个整数数组 nums 请你找出一个具有最大和的连续子数组 子数组最少包含一个元素 返回其最大和 子数组 是数组中的一个连续部分 示例 1 输入 nums 2 1 3 4 1 2 1 5 4 输出 6 解释 连续子数
  • Maven仓库(仓库配置) 配置好你的仓库~

    文章目录 远程仓库的配置 远程仓库的认证 部署至远程仓库 镜像配置 远程仓库的配置 Repositories元素下 可以用repository 子元素声明一个或者多个远程仓库 id 远程仓库的ID 必须唯一 maven自带的中央仓库的id为
  • 使用 OpenSSH 从 PC 机传送文件到CPU板时,CPU板和虚拟机不在一个ip网段无法通信

    本人也是萌新小白 这里主要分享一下自己调试过程中遇到的问题和解决方法 希望能帮到大家 gt lt 项目场景 从PC机的虚拟机的Ubuntu系统传输文件到CPU板系统 问题描述 1 首先是CPU板系统连接不到PC机的网络 2 CPU板系统和P
  • XML - insert

    XML insert 属性 属性 描述 id 命名空间中的唯一标识符 可被用来代表这条语句 parameterType 将要传入语句的参数的完全限定类名或别名 这个属性是可选的 因为 MyBatis 可以通过 TypeHandler 推断出
  • vue项目报错in ./src/app.vue?vue&type=style&index=0&lang=less

    原因 less和less loader版本号过高 解决 先删除原来的再重新安装 npm uninstall less loader npm uninstall less npm install less loader 4 1 0 D npm
  • flutter 设置状态栏的颜色,背景appBar: AppBar( elevation: 0.5, brightness: Brightness.light,

    在有AppBar的界面 状态栏一般有Brightness dark 和Brightness light两种模式 分别是白色的导航栏字体颜色和黑色的字体颜色 appBar AppBar elevation 0 5 brightness Bri
  • 【数据结构】单链表详解

    当我们学完顺序表的时候 我们发现了好多问题如下 中间 头部的插入删除 时间复杂度为O N 增容需要申请新空间 拷贝数据 释放旧空间 会有不小的消耗 增容一般是呈2倍的增长 势必会有一定的空间浪费 例如当前容量为100 满了以后增容到200
  • java混编

    java里面总共有八种基本数据类型 其分别为 byte short char int long float double Boolean 其他都是引用数据类型 而引用数据类型是以对象的形式存在 基本数据类型都可以直接进行运算 没必要先换算成
  • [Python人工智能] 十七.Keras搭建分类神经网络及MNIST数字图像案例分析

    从本专栏开始 作者正式研究Python深度学习 神经网络及人工智能相关知识 前一篇文章详细讲解了Keras环境搭建 入门基础及回归神经网络案例 本篇文章将通过Keras实现分类学习 以MNIST数字图片为例进行讲解 基础性文章 希望对您有所
  • 将时间戳转换成标准时间格式

    标准时间格式 2023 02 01 15 08 56 如果是要转成 2023 02 01 15 08 56 将下列代码拼接的字符串 改成 即可 毫秒时间戳转换时分秒 毫秒时间戳为16位 export function getLocalTim
  • [网络安全自学篇] 四.实验吧CTF实战之WEB渗透和隐写术解密

    最近开始学习网络安全相关知识 接触了好多新术语 感觉自己要学习的东西太多 真是学无止境 也发现了好几个默默无闻写着博客 做着开源的大神 接下来系统分享一些网络安全的自学笔记 希望读者们喜欢 上一篇文章分享了解BurpSuite工具的安装配置
  • Klocwork部署的安全最佳实践

    Klocwork是一款静态代码分析和SAST工具 适用于 C C C Java JavaScript Python和Kotlin 可识别软件安全性 质量和可靠性问题 帮助强制遵守标准 阅读本文 您将了解Klocwork的设置步骤 助力您实现
  • 微信小程序使用.concat()等数组连接爆错原因

    微信小程序数组连接爆错 当我们在微信小程序中使用数组连接时有时候会出下以下的错误 js里面的写法如下 this setData goods this data goods concat res data 其原因的是因为在微信小程序的data
  • 【STM32F407电机控制学习笔记】TIM8输出PWM&触发ADC采集电流cubeMX配置

    时钟配置 高速时钟使用外部晶振 HCLK配置为160MHz 方便后续定时器分频 TIM8配置 TIM8的Channel1 Channel3用于输出两路互补的PWM Channel4 PWM不输出 用于触发ADC采样 中心对齐模式1 计数器在
  • 如果更好的做好MES系统运维

    因人因时因地制宜 治疗疾病要根据人体的体质 性别 年龄等不同 以及季节 地理环境以制定适宜的治疗方法 我觉得mes运维也应该采用相同的方式 下面先了解一下常见的三种运维方式 第一种方式 企业有自己的信息中心 不同的人负责不同的模块 员工职责
  • 使用ant-design-pro-vue时,将登录从mock换成后台出现问题(请求出现错误,请稍后再试)

    因为我不是专门的前端 所以搞这个时 困难重重 在使用这个模板时 我想要将登录换成从后台进行响应 在一开始我是通过项目中的mock文件下的auth js来找到对应的响应数据 看到如上图所示 我心想 稳了 结果我后台就按照这个来造了一个测试 结
  • 孔板流量计计算公式_差压式流量计常用计算公式及计算实例

    差压式流量计维修中计算工作是仪表人不可缺少的 在本文分享差压式流量计常用流量计算公式及计算实例 掌握这些干货技术 对用好差压式流量计有事半功倍效果 流量计算公式1 差压式流量计的差压与流量关系的换算差压式流量计的差压与流量的平方成正比 或者
  • 【Django快速开发实战】(30~51)使用Django创建一个基础应用:职位管理系统

    30 遗留系统集成 为已有系统数据库生成管理后台 流程说明 为已有数据库生成管理后台 创建项目和应用 创建新项目 django admin startproject empmanager 创建新应用 django admin startap