前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >我们的Tornado项目结构

我们的Tornado项目结构

作者头像
the5fire
发布2019-03-01 14:28:43
2K0
发布2019-03-01 14:28:43
举报

Tornado项目结构

之前答应过群里几个同学要晒下我们的Tornado项目结构,后来就忘了。。。今天晒出来。

无论是Tornado项目还是Django的项目,大体结构都是一样的。最外层是工程结构,包含了配置、文档、打包等信息,当然还有源码。

项目结构大体都是这样:

代码语言:javascript
复制
project
    - conf/
    - docs/
    - src/
        - package1/
            - __init__.py
            - models.py
        - manager.py
        - server.py
    - setup.py
    - MANIFEST.in

对于项目来说,只考虑两个问题,第一:本地开发是否方便;第二:线上部署是否方便。

开发方便

Django的./manage.py runserver的方式对于本地开发调试就很方便,所以对于Tornado项目来说,也需要有一个类似的机制可以方便的在开发环境中启动项目。

部署方便

因为我们是采用标准的PyPi包分发的方式部署的项目,所有项目文件最终都会落到site-packages中,所以包目录的规划就是个问题。

比如像Django那样,把所有的App作为独立的包分散到site-packages中,还是把源码目录"src"作为独立的包放到site-packages中。

两种不同的方式,在启动时也有所差别,因为包的路径是不一样的。这里不讨论哪种方式更合理,我们只说实际的使用情况。

所以部署方便的点在于,我把包放到site-packages中后是否能方便的启动项目。这意味着包的结构需要兼容本地启动和线上启动。

本地和线上的差别

所以就扯到另外一个问题,本地启动项目时,你当前脚本所在的目录就是默认的包根目录,也就是在sys.path中会加入当前文件所在目录,也就是上面结构中的project/src。你要引用package1下的模块,直接from package1.models import xxxx即可。

而在线上的情况是,源码目录是作为独立包放在site-packages中的。你要引用的话需要from src.package1.models import xxx

这种本地和线上不同引用的问题在Django中是没有的,除非你调整了Django的结构。

问题解决

包的依赖路径问题,基本上都可以通过sys.path.insert(<path>)来解决。

两种解决的方式,一个是改线上的sys.path,一个是改本地的。线上的改动只需要在项目加载时把src目录先insert到sys.path中,作为一个新的根路径。

另外一个就是改本地的启动命令,把src所在的目录加到sys.path中。

从个人的习惯来说,能调整本地逻辑的就不去修改部署环境的逻辑,让其按照默认的方式处理是最稳当的方式。毕竟线上挂了影响很大。

所以我会在本地启动项目是做上面的处理,同时所有包的引用触发是同包的情况下,否则都需要从src开始,也就是:from src.package1.models import xx

最终目录结构

代码语言:javascript
复制
project
   ├── MANIFEST.in
   ├── README.md
   ├── conf
   │   └── supervisord.conf
   ├── fabfile
   │   ├── __init__.py
   ├── requirements.txt
   ├── setup.cfg
   ├── setup.py
   └── project_src
       ├── __init__.py
       ├── handlers
       │   ├── __init__.py
       │   ├── base.py
       │   ├── index.py
       ├── server.py
       ├── settings
       │   ├── __init__.py
       │   ├── base.py
       │   └── develop.py
       ├── templates
       │   └── base.html
       ├── url.py
       └── models
           ├── __init__.py
           ├── model1.py
           └── model2.py

其中一server.py的示例代码如下:

代码语言:javascript
复制
#!/usr/bin/env python
import os
import sys
from logging.config import dictConfig
from importlib import import_module

import click
import tornado.ioloop
import tornado.web
from raven.contrib.tornado import AsyncSentryClient


def make_app(debug=None):
    from project_src.url import urls
    assert isinstance(urls, (list, tuple)), 'urls must be list or tuple'
    return tornado.web.Application(urls, debug=debug)


def init_log():
    dictConfig(tornado.settings.LOGGING)


@click.command()
@click.option('--port', default=9090)
@click.option('--profile', default='develop')
def serve(port, profile):
    settings = import_module(f'project_src.settings.{profile}')
    tornado.settings = settings
    init_log()

    app = make_app(settings.DEBUG)
    app.listen(port)
    app.sentry_client = AsyncSentryClient(
        '<sentry>'
    )
    sys.stdout.write(f"Start server at:http://0.0.0.0:{port} \nProfile: {profile}\n")
    tornado.ioloop.IOLoop.current().start()


if __name__ == "__main__":
    current_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    sys.path.insert(0, current_path)
    serve()

最后

其实无论哪种方式,只要能够保证大家保有共识就可以,比如the5fire不去修改线上的加载路径,目的是避免有人去按照常识去修改包目录之后产生不可预知的后果。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-07-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Tornado项目结构
    • 开发方便
      • 部署方便
        • 本地和线上的差别
          • 问题解决
            • 最终目录结构
              • 最后
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档