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 · 11335 次点击
    这是一个创建于 3257 天前的主题,其中的信息可能已经有所发展或是发生改变。

    作为一个「人生苦短,我用 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   ·   实用小工具   ·   2855 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 00:06 · PVG 08:06 · LAX 16:06 · JFK 19:06
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.