原因
在公司的研发团队中,我除了要写代码,还要做一些项目架构和基础设施搭建的工作,每次搭建一个新项目都会有不少重复的工作,一两次还好,多了我真的有点受不了,于是思索着写这么一个东西来减少工作的痛苦。
技术架构
工作中主要使用 Python,API 主要使用 Django、Django RESTframework 来做,一些 Python 依赖和目录结构都是统一的,我就先减少这部分的重复工作吧。
requirements
Django==1.9.10 django-cors-headers==1.1.0 django-nose==1.4.4 django-rest-swagger==0.3.7 djangorestframework==3.4.6 djangorestframework-jwt==1.8.0 mysqlclient==1.3.7 raven==5.26.0
Django 使用 1.9.10 的原因是这个版本和 django-rest-swagger 的 0.3.7 版本配合比较好,比较适合我们团队, 可以很方便的在浏览器下调试,效果如下:
- django-cors-headers 用来解决前端请求接口的跨域问题。
- djangorestframework-jwt 用来解决接口的 Token Auth 问题。
- mysqlclient Python 的 MySQL 驱动,支持 Python 3。
- raven Sentry 的客户端,用于记录生产环境用户遇到 500 异常。
目录结构
├── .gitignore # python 的 gitignore 文件 ├── .venv # virtualenv ├── manage.py ├── requirements # python 依赖 │ ├── base.txt │ ├── dev.txt │ └── prod.txt └── webapi # 项目代码 ├── __init__.py ├── admin.py # model 统一添加到 django admin 中 ├── migrations │ └── __init__.py ├── models # models │ └── __init__.py ├── settings # settings │ ├── __init__.py │ ├── local_settings.py.tpl │ └── settings.py ├── urls.py └── wsgi.py
requirements 做成一个文件夹是考虑到 开发环境 的依赖和 生产环境 可能会有区别。
models 做成一个文件夹是因为我们想在一个地方统一管理所有 models 而不是分散在各个 app 中。
models/__init__.py
的代码
# coding: utf-8 # 每新增一个 models 文件,就添加一行 import 代码 # from .your_models import *
settings 做成一个文件夹是为了区分 开发环境 和 生产环境 的配置。
秘密都藏在 settings/__init__.py
文件中。
# coding: utf-8 from .settings import * try: from .local_settings import * except: pass
admin.py 功能是把所有 models 添加到 django admin 中,方便开发过程中的调试。
admin.py
代码
# coding: utf-8 import inspect from django.contrib import admin import models as app_models for attr in dir(app_models): model = getattr(app_models, attr) if not inspect.isclass(model): continue try: admin.site.register(model) except: pass
settings 的额外配置
import datetime # django restframework app INSTALLED_APPS += [ 'rest_framework', 'rest_framework_jwt', 'rest_framework_swagger', 'corsheaders', ] # Django REST Framework settings REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', ), 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', ), 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 20, 'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser', ), 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer', ), } # jwt auth settings JWT_AUTH = { 'JWT_ENCODE_HANDLER': 'rest_framework_jwt.utils.jwt_encode_handler', 'JWT_DECODE_HANDLER': 'rest_framework_jwt.utils.jwt_decode_handler', 'JWT_PAYLOAD_HANDLER': 'rest_framework_jwt.utils.jwt_payload_handler', 'JWT_PAYLOAD_GET_USER_ID_HANDLER': 'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler', 'JWT_RESPONSE_PAYLOAD_HANDLER': 'rest_framework_jwt.utils.jwt_response_payload_handler', 'JWT_SECRET_KEY': SECRET_KEY, 'JWT_ALGORITHM': 'HS512', 'JWT_VERIFY': True, 'JWT_VERIFY_EXPIRATION': True, 'JWT_LEEWAY': 0, 'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=60 * 60 * 24), 'JWT_ALLOW_REFRESH': False, 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7), 'JWT_AUTH_HEADER_PREFIX': 'JWT', } # cors header CORS_ORIGIN_ALLOW_ALL = True
以上的模板可以在 django-starter-template 里找到。
技术思路
我的需求
- 最终效果是使用
djkit init your_project
一条命令搞定项目初始化。 - 写成一个库,使用 pip 可以安装,方便以后升级。
技术调研
命令行工具的选用,经过了各种筛选,最终使用了 click 这个库来做命令行工具的解析,原因很简单,
个人直觉。
文件的操作我就直接使用了笨办法,subprocess 调用 shell 命令解决。
初始化流程
- clone django-starter-template 到 /tmp 目录。
- /tmp 目录初始化一个 virtualenv 里面安装 django 1.9.10。
- 使用
django-admin.py startproject your_project
初始化项目。 - 生成的项目中初始化 virtualenv 安装 requirements 的依赖。
- 复制 django-starter-template 模板的代码到生成的项目中。
- 删除 /tmp 下生成的临时文件。
实现
目录结构
├── LICENSE
├── README.md
├── bin
│ └── djkit
├── djkit
│ ├── __init__.py
│ └── djkit.py
└── setup.py
核心代码在 djkit/djkit.py
里。
所有代码实现在 djkit 项目,对细节感兴趣的可以去看源代码。
写成 Python 库
只需要一个 setup.py
搞定。
# coding: utf-8 from setuptools import setup setup( name='djkit', version='0.3', description='django starter kit', url='https://github.com/BurnishTechCN/djkit', author='runforever', author_email='c.chenchao.c@gmail.com', license='WTFPL', packages=['djkit'], install_requires=[ 'virtualenv', 'click', ], scripts = ['bin/djkit'], zip_safe=False, )
程序入口 bin/djkit
文件,依然是 Python
#!/usr/bin/env python from djkit import djkit djkit.cli()
安装和使用
pip install . # 或者 pip install git+https://github.com/BurnishTechCN/djkit.git # 使用 djkit init webapi
开源和 License
没有开源社区,我写不出来这个工具,所以依旧开源回馈社区,如果能解决到别人的问题,那就达到效果了, 不知道从哪听来的 WTFPL,感觉碉堡了,于是就他了。