Django admin 的使用
初始化
创建项目:
manage.py startproject project_x
创建应用:
manage.py startapp app_x
创建管理用户:
manage.py createsuperuser
在 app_x 里面的 models.py 文件中,创建数据库字段(建模),涉及到字段改动时,为了保证数据安全性,建议只新增字段而不直接修改原来的字段,防止 migrate 时操作数据库时出现问题。
1
2
3
4
5
6
7
8# 使用系统自带的鉴权功能
from django.contrib.auth.models import User
JobTypes = [(0, "技术类"),(1, "产品类"),(2, "运营类"),]
class Job(models.Model):
creator = models.Foreignkey(User,verbose_name="创建人")
# 使用下拉选项,需要定义一个列表 JobTypes
job_type = models.SmallIntegerField(
blank=False, choices=JobTypes, verbose_name="职位类别",help_text="页面上显示的帮助信息。")
之后在 admin.py 中注册新建的模型,使其可以在管理页面中进行维护
1
2from models import Job
admin.site.register(Job)在 setting.py 的 INSTALLED_APPS 中,注册当前应用
1
INSTALLED_APPS = ['...','jobmanage',]
执行数据库同步(迁移)
1
2manage.py makemigrations
manage.py migrate运行。
修改日期为自动填充
在 models.py 模型里面,修改时间为自动填充,通过引用 datetime 函数来实现
1 | class Job(models.Model): |
在 admin 中创建管理类
通过管理类,来控制前端的信息,如显示信息、过滤信息等
1 | # admin.py |
添加自定义页面
定义一个 base 页面,作为所有页面的模板,子页面通过 block 来填充内容;
1
2
3
4
5
6
7
8<!-- base.html -->
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<h1 style="margin:auto;width:50%">这是首页</h1>
{% block content %}
{% endblock %}子页面继承 base 页面
1
2
3
4
5
6
7
8{% extends "base.html" %}
{% block content %}
这里是子页面的信息
{% if xxx %}
{% else %}
{% endif %}
{% endblock %}
使用管理工具管理命令行脚本
在 app 目录下创建 management/commands 目录,里面放入脚本,之后可以使用 manage.py 进行执行调用。
例如,实现从 csv 导入数据的功能。
1 | import csv |
之后使用命令行来执行命令,就可以成功导入数据:
1 | manage.py import_candidates --help |
Django 和 LDAP 集成
安装:
1 | pip install django-python3-ldap |
在 setting.py 中注册 APP
1 | INSTALLED_APPS = ['...','django_python3_ldap',] |
在 setting.py 中配置 LDAP
1 | ### LDAP |
域用户初次登陆时,Django 会把用户信息在 Django 的表中进行创建,此时用户并没有登录权限,需要设置为 STUFF 才可以正常登录,还需要为用户配置权限,否则登录进去没有任何权限,显示空白。
可以使用命令行来一键从 LDAP 同步账户,然后在 Django 页面中为用户设置登录权限以及不同的查看或者编辑权限。
1 | manage.py ldap_sync_users |
在 admin 管理类中自定义动作(Action)
默认情况下,Django 的管理页面只有针对数据的删除操作,可以在 admin.py 中定义函数并进行注册。
1 | # 自定义一个功能(函数) |
可以添加各种方法来对数据进行操作,例如发邮件告警等。
添加 LOG
1 | import logging |
多环境配置文件分离
在项目根目录下新建一个 settings 的包,然后根据不同的开发环境等需求,对配置文件进行分离。
重组目录后,还需要在项目的 manage.py 中进行修改,修改为新目录下的文件。
os.environ.setdefault(key, value)
是为当前系统设置一个环境变量。
1 | # manage.py |
在 settings 目录下,添加生产环境的配置信息:
1 | # production.py |
在 settings 目录下,添加开发环境的配置信息:
1 | # dev.py |
指定环境启动项目
1 | manage.py runserver 0.0.0.0:8000 --settings=settings.dev |
原理:在命令行指定 --settings
之后,就会替换 manage.py 中的 DJANGO_SETTING_MODULE
选项。
设置站点标题、多语言
在默认 APP 的 url.py 中进行配置:
1 | # django_demo/url.py |
修改默认的管理界面
1 | # 先安装界面 |
安装成功后,在 settings.py 中将主题注册一下,注意:主题注册要位于 admin 的前面
1 | INSTALLED_APPS = ('grappelli', 'django.contrib,admin',) |
在 url.py 中添加 URL 映射,也要位于 admin 的前面
1 | urlpaterns = [ |
权限管理
数据权限、数据集权限
admin.py 中,在数据的管理类里面定义各类显示函数,通过判断来实现:
1 | class TestModelAdmin(admin.ModelAdmin): |
功能(Action)权限(菜单、按钮等)
需要在 models 里面定义 Meta 类,添加权限并迁移数据库
1
2
3
4
5
6
7
8
9# models.py
class Job(models.Model):
class Meta:
# 定义权限,然后在 admin.py 中为具体的功能添加权限
permissions = [
("export", "Can export db"),
("notify", "Can notify message"),
]在 admin.py 中为功能添加权限
1
2
3
4
5# admin.py
def some_actions(modeladmin, request, queryset):
pass
some_actions.allowed_permissions = ("export",)在模型管理类中添加权限判断
1
2
3
4
5# admin.py
class TestModelAdmin(admin.ModelAdmin):
def has_export_permission(self, request):
opts = self.opts
return request.user.has_perm('%s.%s'% (opts.app_label,"export"))在 admin web 管理后台中,按需为具体的用户配置权限。
webhook 通知(钉钉为例)
安装钉钉机器人
1
pip install DingtalkChatbot
在钉钉中创建群聊机器人,获取 webhook 地址,并在 settings 中配置
在 APP 目录下定义一个发送消息的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14# some_app/dingtalk.py
from dingtalkchatbot.chatbot import DingtalkChatbot
from django.conf import settings
def send_msg(message, at_mobiles=[]):
# 引用 settings 里面的 webhook 配置地址
webhook = settings.DINGTALK_WEBHOOK
secret = settings.SECRET
# 初始化一个机器人
bot = DingtalkChatbot(webhook)
# 示例2:如果机器人勾选了“加签”,需要传入 secret
bot2 = DingtalkChatbot(webhook=webhook,secret=secret)
# 发送消息
bot.send_text(msg="WebHook 机器人测试", at_mobiles=at_mobiles)在 admin.py 中新增 action
1
2
3
4
5
6
7
8
9
10# admin.py
from django.contrib import messages
from some_app import dingtalk
def notify(modeladmin, request, queryset):
msg = "测试消息:\n"
for obj in queryset:
msg += "%s 的手机号是 %s\n" %( obj.username, obj.phone)
dingtalk.send_msg(msg)
messages.add_message(request, messages.INFO, "发送成功")在 管理类中注册 action
1
2
3# admin.py
class TestModelAdmin(admin.ModelAdmin):
actions = ["notify",]可以使用 django shell 进行消息测试
1
2
3manage.py shell
from some_app import dingtalk
dingtalk.send_msg("测试消息")
添加一个第三方注册功能的 APP
先安装第三方包
1 | pip install django-registration-redux |
在 settings 中注册
1 | INSTALLED_APPS = ["registration",] |
在 url.py 中添加 URL 映射
1 | # url.py |
迁移数据库
1 | manage.py makemigrations |
启动服务,访问测试
1 | http://localhost:8000/accounts/register |
配置注册完成后跳转到登录页面
1 | # settings.py |
添加前端页面(view)
一般情况下,如果写 view 的话,全部字段都是需要自定义的;
可以使用 Django 自带的通用 view,自定义 view 继承通用的 view,常见的有 CreateView(表单)、DetailView(详情页)、ListView(列表),官方教程见:基于类的表单视图
1 | from django.views.generic.edit import CreateView |
然后在 url.py 里面注册路径,格式固定为 类.as_view()
:
1 | urlpatterns = [ |
最后添加前端模板页面 resume_form.html ,模板名字也是推荐使用固定后缀,表单页是 _form.html
,详情页是 _detail.html
,列表页是 _list.html
。
1 | <!-- resume_form.html --> |
使用 bootstrap 美化页面
安装 bootstrap4
1 | pip install django-bootstrap4 |
在 settings.py 中注册
1 | INSTALLED_APPS = ["bootstrap4",] |
在 html 中添加 bootstrap
1 | {# 加载 bootstrap 库 #} |
为已经有的系统添加管理后台
首先在 settings.py 中添加已有环境的数据库配置
然后使用 manage.py 命令为现有数据库生成 model
1 | manage.py inspectdb > models.py |
添加多语言
- 代码中使用
gettext
gettext_lazy
获取多语言资源对应的文本内容 - 生成多语言资源文件
- 翻译
- 生成二进制多语言资源文件
- 页面配置按钮
错误上报到 sentry
和 Celery 结合,用 Flowers 查看 redis 性能
多数据库路由,实现读写分离/整合现有数据库
大量数据的关联外键
场景:依赖外量数据量过大导致页面卡死;比如添加一个员工,员工的出生地依赖于城市表,全球城市表有上万个,使用下拉框选择时,Django 默认会把外键中的所有数据都加载
数据关系:City 从属于 Province,Province 依赖于 Country
期望:选择依赖的数据时,可输入字符进行查找
解决方案:在 admin.py 中设置字段为自动完成
1 | # models.py 中的外键关系 |
多级数据自动关联
选择某个数据的时候,其他与它相关的字段内容自动关联发生改变。例如选择一个城市,自动关联出省份和国家。
使用如下插件来实现:
1 | pip install django-smart-selects |
将插件注册到 APP 中,然后在 url.py 中添加路径,下拉选择时会调用此路径
1 | urlpatterns = patterns( |
最后在 Model 中定义 ChainedForeginKey
外键:
1 | class City(models.Model): |
定义只读的管理后台(重写 admin.ModelAdmin 方法)
对集成的原有系统,为了安全起见,提供只读的管理后台,定义一个 ReadOnlyAdmin,然后其他的 model 继承这个只读的 Admin。
1 | class ReadOnlyAdmin(admin.ModelAdmin): |
自动注册所有的 Model 到管理后台
在根下创建 apps.py 里面遍历 models ,注册这个 app
1 | from django.contrib import admin |
使用动态类的方法
Python 中类也是对象,利用动态特性,使用 type() 函数动态顶一个类
1 | model = type(name, (models.Model,), attrs) |
现成模块:sandman,为已有数据库提供增删改查和 RestAPI
信号处理
有信号发生的时候,帮助解耦的应用接收到消息通知,允许特定的信号发送者发送消息到一系列的消息接收者。是同步调用。
例如,当某个数据发生改变时,发送邮件通知消息。
常用插件
- Django debug toolbar:提供可以查看 debug 信息的面板,包括 SQL 执行时间,页面耗时等
- django-silk:性能瓶颈分析
- simple ui : 基于 Element UI 和 Vue 的主题
- Haystack Django:模块化搜索方案,全文搜索,使用不同的搜索系统
- Django notifications:发送消息通知
- Django markdown editor:编辑器
- Django-crispy-forms:Crispy 表单,以一种优雅、干净的方式常见美观的表单
- django-simple-captcha:表单验证码,可以防止攻击
- django-ratelimit:应用限流
- django-user-accounts:密码安全
部署到生产环境之前
单元测试
TestCase
哪些逻辑需要测试?
自带的代码可以不用测试,对自己写的代码进行测试,如自定义页面、自定义菜单
目录结构,testcase 文件夹下,匹配 test*.py 的文件作为测试用例。
执行测试: manage.py test
配置生产环境
- DEBUG 、Secret 、ALLOWED_HOSTS 等相关信息
- Django APP 的托管环境选择,云上还是云下
- 部署前的检查 manage.py check –deploy
- 静态资源文件的托管环境(JS、CSS、图片、文件等)& 部署静态资源(manage.py collectstatic 工具收集所有静态资源)
- 部署 Django 应用容器和 Web 服务器(uWSGI、gunicorn、Daphne、Hypercorn、Uvicorn),不提供静态资源的加载,静态资源要放在前端 Nginx 上
用户(www.baidu.com)---> Nginx 服务器(proxy_pass localhost;) —> Django Server
应用部署架构
密钥管理:文件、环境变量、KeyServer
开源的 KeyServer:vault、keywhiz、knox
免费的 SSL 证书机构:Let’s Encrypt,90 天到期,可以自动续期。
技术方案设计与拆解
定义用户场景 –> 业务流程 –> 产品范围 –> 梳理核心要解决的问题 –> 调研对比不同的方案 –> 系统的模块界限、协议、数据流转、数据输入输出 –> 形成文档 –> 开发&测试 –> 发布
用到的工具:不用工具是最好的工具,白纸、白板,完成后再到线上。
Visual Paradigm、Lucid Chart、Visio、Draw.io、StarUML、Gliffy
技术方案设计文档要素:
- 产品背景(用户场景、产品目标、业务流程、需求文档)
- 要解决的问题、不解决的问题、系统的限制
- 问题的不通解决方案对比
- 整体的流程图、模块关系图、重要的接口、实体的概念定义
- 除了核心功能外的其他方面的设计,如安全、性能、可维护、稳定性、监控、扩展性、易用性
工作拆解:任何事情只要拆的足够细,都能够完成它
拆解原则:
- 优先级:主流程上,不确定的工作优先完成
- 核心流程优先:核心工作优先,先把主流程跑通
- 依赖:人员之间工作依赖
- 拆解粒度:拆解每项子任务 0.5~1 天的粒度,最长不超过两天