[新手开源] 使用 Tornado 搭建 RESTful 接口服务 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
nekocode
V2EX    Python

[新手开源] 使用 Tornado 搭建 RESTful 接口服务

  •  1
     
  •   nekocode
    nekocode 2016-01-21 01:18:01 +08:00 11653 次点击
    这是一个创建于 3559 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作为一个「人生苦短,我用 Python 」的程序员,最近毅然决然地决定使用 Tornado 搭建一个社交应用的服务后端。现在在开发途中积累了很多不错的东西,打算分享给有这方面需求的人。

    我在开发该社交应用(图片问答社区)中,使用了以下一些工具:
    Tornado , MongoDB , Redis , Qiniu , MQTT

    说实话, MongoDB 真的挺适合储存社交数据的,不过 Tornado 下真的缺乏一款好用的 MongoDB 的 ORM 框架, Motor Engine 还缺乏很多功能。不知道有没有大牛能够推荐一下。

    另外就是目前在实现用户 Feeds 时有些停顿,目前仍在研究如何处理会好一些,也希望有经验的大牛能提供下好的意见。

    去掉大部分的业务逻辑的壳,需要的拿去,也欢迎 Star , PR :
    TornaREST . Github

    32 条回复    2016-02-01 19:24:27 +08:00
    dai269619118
        1
    dai269619118  
       2016-01-21 09:31:25 +08:00
    支持一下 有空了下载过来看下
    nekocode
        2
    nekocode  
    OP
       2016-01-21 09:56:36 +08:00
    @dai269619118 谢谢支持~
    tonghuashuai
        3
    tonghuashuai  
       2016-01-21 10:04:49 +08:00
    MongoDB 的 ORM 我们用的 pymongo ,然后做了一点修改,使用起来完全无痛,非常顺手
    nekocode
        4
    nekocode  
    OP
       2016-01-21 10:10:21 +08:00
    做的修改是让 pymongo 支持异步?

    这里有一篇文章,是针对 tornado 下的 ORM 框架的对比测试,你可以看看:
    http://www.cnblogs.com/restran/p/4937673.html
    nekocode
        5
    nekocode  
    OP
       2016-01-21 10:10:30 +08:00
    withrock
        6
    withrock  
       2016-01-21 10:22:41 +08:00
    刚好派上用场,请收下我的膝盖!
    withrock
        7
    withrock  
       2016-01-21 10:24:55 +08:00   1
    就是对你起的这个项目名称不太满意
    tornado + rest = tornaRST ???
    tonghuashuai
        8
    tonghuashuai  
       2016-01-21 10:33:14 +08:00
    @nekocode
    也没什么大修改,就是根据 model 名字自动设置 __collection__ 以及加了个迭代查询的方法
    nekocode
        9
    nekocode  
    OP
       2016-01-21 10:33:25 +08:00
    @withrock
    tornado 和 REST 是不同概念的东西,无法相提并论,所以我用的是 & 操作符,而不是 +。至于名称的话,不用太在意,随便起的而已 ε
    mapleray
        10
    mapleray  
       2016-01-21 10:50:17 +08:00
    弱弱问下,`user = yield User.objects.get(user_id)` 和 `schools = yield School.objects.find_all()` 这里用`yield` 的好处?没怎么看懂...
    ethego
        11
    ethego  
       2016-01-21 11:06:30 +08:00
    用 gevent 另外包一个线程或者开一个线程池代理 pymongo , tornado 的数据库请求全往这里发,应该可以解决阻塞的问题。
    phithon
        12
    phithon  
       2016-01-21 11:18:28 +08:00
    并没有用 orm ,好像没见过有异步的 orm ?求推荐, mysql/mongo
    ethego
        13
    ethego  
       2016-01-21 11:28:35 +08:00
    @phithon 没必要,异步也是在 orm 外部做, orm 不是干这个的。
    strahe
        14
    strahe  
       2016-01-21 11:44:25 +08:00
    一直用 pymongo , mongodb 原生的操作更爽,你只是需要稍微适应一下
    cloudzhou
        15
    cloudzhou  
       2016-01-21 11:52:39 +08:00
    我想问一下 mqtt 用在哪里?
    nekocode
        16
    nekocode  
    OP
       2016-01-21 13:03:08 +08:00
    @mapleray
    这是利用 yield 关键字来实现异步操作,具体实现要看 tornado 的 gen 装饰器。


    @phithon
    @strahe
    我之前在使用 MySQL 的时候,一直用的是 torndb ,也并非 ORM 库。


    @cloudzhou
    MQTT 用在实现消息推送上, MQTT 比起其他协议(例如 XMPP )简单高效多了。
    ericls
        17
    ericls  
       2016-01-21 13:09:29 +08:00
    motor 在 aiohttp 下还是很不错哒感觉
    nekocode
        18
    nekocode  
    OP
       2016-01-21 18:03:59 +08:00
    @ericls 异步实现上,好像也就 motor 靠谱些了
    latyas
        19
    latyas  
       2016-01-21 18:10:07 +08:00
    ThreadPool + pymongo 保证没坑
    用 motor 的话还是悠着点好
    phithon
        20
    phithon  
       2016-01-21 18:32:51 +08:00
    @ethego
    我知道 orm 不是干这个的,但具体怎么实现『在外部做』,求指导?
    有封装了的可以直接用的么?
    zhuf
        21
    zhuf  
       2016-01-22 11:22:08 +08:00
    mongoengine 啊
    nekocode
        22
    nekocode  
    OP
       2016-01-22 11:32:06 +08:00
    @latyas 实现起来太麻烦了。

    @phithon https://motor.readthedocs.org/en/latest/index.html

    @zhuf mongoengine 不是非阻塞的。 motorengine 是 mongoengine 针对 tornado 的 port 版本。
    neoblackcap
        23
    neoblackcap  
       2016-01-22 12:10:54 +08:00
    @phithon 要不就是多线程 /多进程池,要不就是消息队列。再来就是 microservice ,然后用 AsyncHttpClient 调用。

    PS :毕竟数据库操作都是 IO 密集型,因此用多线程也是可以的。
    fhefh
        24
    fhefh  
       2016-01-22 14:43:24 +08:00
    学习了 mark
    SaberSalv
        25
    SaberSalv  
       2016-01-22 15:41:11 +08:00
    为什么都喜欢绑定? 比如我不想用 MongoDB 怎么办?
    nekocode
        26
    nekocode  
    OP
       2016-01-22 15:58:02 +08:00
    @SaberSalv 很抱歉,我并没有把它做成可拆卸的,想使用 MySQL 的话必须自己修改代码(推荐使用 torndb )。我写它的出发点在于创建一个提供社交接口的高性能的后端,所以在栈选择上比较极端。
    phithon
        27
    phithon  
       2016-01-22 17:50:41 +08:00
    @nekocode
    这个并不是 orm 呀。。。我写的一个项目就是用的 motor https://github.com/phith0n/Minos
    nekocode
        28
    nekocode  
    OP
       2016-01-22 18:21:40 +08:00
    @phithon
    需要 ORM 的话可以看看这个: https://github.com/heynemann/motorengine
    我在代码里面就是使用它的,具体可以查阅我的 Github Repo
    phithon
        29
    phithon  
       2016-01-22 18:43:53 +08:00
    @nekocode 已关注~
    anson008
        30
    anson008  
       2016-01-23 11:17:00 +08:00
    https://github.com/PyMySQL/Tornado-MySQL
    我目前一个 websocket 项目中用的 tornado+异步 mysql db 读写
    希望和大家多多交流
    latyas
        31
    latyas  
       2016-01-25 13:08:27 +08:00
    @nekocode 不麻烦

    from concurrent.futures import ThreadPoolExecutor

    tpool = ThreadPoolExecutor()

    asyncio 的话 await asyncio.wrap_future(tpool.submit(target, *args, **kwargs)) 即可,
    tornado 也有用 concurrent 库的接口。
    withrock
        32
    withrock  
       2016-02-01 19:24:27 +08:00
    @gen.coroutine
    13 def get_all_gallerys():
    14 gallery_path = "/mnt/F/Picture"
    15 gallerys = []
    16 for item in os.listdir(gallery_path):
    17 if not os.path.isdir(item):
    18 continue
    19 gallery = dict(
    20 name = item,
    21 path = os.path.join(gallery_path, item)
    22 )
    23 gallerys.append(gallery)
    24 raise gen.Return(gallerys)
    25
    26 class GalleryHandler(BaseHandler):
    27 def data_received(self, chunk):
    28 pass
    29
    30 @tornado.web.asynchronous
    31 @gen.coroutine
    32 def get(self):
    33 ret = yield get_all_gallerys()
    34 print ret
    35 self.write_json(ret)


    @nekocode
    请问这样调用,想在这个 handle 里返回一个目录下的所有文件夹,但是返回的消息却是
    {"msg": "success.", "code": 200, "data": []}
    后台没有打印报错信息
    只是: 304 GET /api/photo/gallerys (::1)
    请问这样该怎么办呢?
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1501 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 29ms UTC 16:28 PVG 00:28 LAX 09:28 JFK 12:28
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86