摘要:中常用的幾個(gè)框架有等,今天來(lái)總結(jié)一下和的不同。本文使用的環(huán)境是。文件可以加載路由信息和項(xiàng)目配置信息,文件負(fù)責(zé)啟動(dòng)項(xiàng)目。以上就簡(jiǎn)單的比較了和幾個(gè)方面的不同,它們各有優(yōu)缺點(diǎn),實(shí)際工作中可以根據(jù)不同的需求選擇不同的框架進(jìn)行開發(fā)。
python中常用的幾個(gè)web框架有django, tornado, flask等,今天來(lái)總結(jié)一下django和tornado的不同。工作中django和tornado都用過(guò),使用django相對(duì)更多一些。個(gè)人感覺(jué)django雖然好用,有搭建項(xiàng)目快、自帶ORM、自動(dòng)生成路由、自帶管理后臺(tái)等優(yōu)勢(shì);但若實(shí)際工作中選擇,我還是會(huì)偏向于使用tornado框架,因?yàn)閠orndo使用更加靈活,并且支持websocket,tcp等通信協(xié)議,最重要的是tornado是異步非阻塞的web框架;而在django中要實(shí)現(xiàn)websocket、異步非阻塞等功能則需要引入dwebsocket、celery等第三方模塊。
本文使用的環(huán)境是python3.6, django2.0, tornado5.1。
下面主要從以下幾個(gè)方面介紹一下這兩個(gè)框架的不同:
1.創(chuàng)建項(xiàng)目的方式
2.數(shù)據(jù)庫(kù)連接
3.異步非阻塞請(qǐng)求
4.websocket的使用
1.項(xiàng)目創(chuàng)建方式
1)django
django主要是通過(guò)下面兩個(gè)命令創(chuàng)建項(xiàng)目:
django-admin startproject Test # 創(chuàng)建項(xiàng)目,名稱為Test django-admin startpapp Test01 # 創(chuàng)建app,名稱為Test01
執(zhí)行完成后,會(huì)生成如下的目錄結(jié)構(gòu):
D:. │ manage.py │ test.txt │ ├─.idea │ │ misc.xml │ │ modules.xml │ │ Test.iml │ │ workspace.xml │ │ │ └─inspectionProfiles │ profiles_settings.xml │ ├─Test │ settings.py │ urls.py │ wsgi.py │ __init__.py │ └─Test01 │ admin.py │ apps.py │ models.py │ tests.py │ views.py │ __init__.py │ └─migrations __init__.py
主要是manage.py,Test,Test01這幾個(gè)文件和文件夾,
manage.py是管理項(xiàng)目的文件,通過(guò)它運(yùn)行django的一些內(nèi)置命令,如模型遷移、啟動(dòng)項(xiàng)目等;
Test/settings.py是配置文件,項(xiàng)目配置存放在這里
Test/urls.py是路由文件,負(fù)責(zé)分發(fā)http請(qǐng)求
Test01/models.py是模型文件,Test01下創(chuàng)建的模型就放在這里,模型負(fù)責(zé)將表結(jié)構(gòu)映射到數(shù)據(jù)庫(kù)中
Test01/views.py是視圖文件,django中的視圖在這里定義
Test01/migrations目錄中存放遷移后生成的遷移文件。
django項(xiàng)目的基本結(jié)構(gòu)就是這樣。
2)tornado
tornado項(xiàng)目的創(chuàng)建比較靈活,沒(méi)有什么項(xiàng)目名稱和app的概念,全靠自己組織項(xiàng)目,就是創(chuàng)建一個(gè)個(gè)python文件和python package。可以像下面一樣來(lái)組織tornado項(xiàng)目:
├── App │ ├── __init__.py │ ├── Shop │ │ ├── __init__.py │ │ └── views.py │ └── User │ ├── __init__.py │ └── views.py ├── application.py ├── Config │ ├── config_base.py │ ├── config_db.conf │ ├── config_db_get.py │ ├── config_engine.py │ ├── __init__.py ├── Models │ ├── __init__.py │ ├── Shop │ │ └── __init__.py │ └── User │ ├── BaseClass.py │ ├── __init__.py │ └── UserModel.py ├── server.py ├── static │ └── __init__.py ├── templates │ └── __init__.py ├── test.py └── Urls ├── __init__.py ├── Shop.py └── User.py
這里有幾個(gè)主要文件App, Config, Models, Urls, static, templates, application.py, server.py。
項(xiàng)目的app可以集中放在App目錄中,與數(shù)據(jù)庫(kù)對(duì)應(yīng)的模型文件可以放在Models中,http路由可以放在Urls中,項(xiàng)目配置信息可以放在Config目錄中,靜態(tài)文件和模板分別放在static和templates中。application.py文件可以加載路由信息和項(xiàng)目配置信息,server.py文件負(fù)責(zé)啟動(dòng)項(xiàng)目。
項(xiàng)目的基本配置信息可以放在Config/config_base.py中,如下:
# coding=utf-8 import os BASE_DIR = os.path.dirname(__file__) # 參數(shù) options = { "port": 8001, } # 基本配置信息 settings = { "debug": True, "static_path": os.path.join(BASE_DIR, "static"), "template_path": os.path.join(BASE_DIR, "templates") }
路由信息可以放在Urls/User.py中,如下:
# coding=utf-8 from App.UserInfo import views user_urls = [ (r"/user/", views.IndexHandler), ]
application.py中加載路由信息和配置信息:
# coding=utf-8 from tornado import ioloop, httpserver from application import Application from Config import config_base if __name__ == "__main__": app = Application() http_server = httpserver.HTTPServer(app) http_server.listen(config_base.options.get("port")) ioloop.IOLoop.current().start()
2.數(shù)據(jù)庫(kù)連接
1)django
django中使用數(shù)據(jù)庫(kù)時(shí),首先要在settings.py中配置數(shù)據(jù)庫(kù)信息:
DATABASES = { "default": { "ENGINE": "django.db.backends.mysql", # 數(shù)據(jù)庫(kù)引擎 "NAME": "django_test", # 你要存儲(chǔ)數(shù)據(jù)的庫(kù)名,事先要?jiǎng)?chuàng)建之 "USER": "root", # 數(shù)據(jù)庫(kù)用戶名 "PASSWORD": "test", # 密碼 "HOST": "localhost", # 主機(jī) "PORT": "3306", # 數(shù)據(jù)庫(kù)使用的端口 } }
然后在每個(gè)app下編寫完models.py后,執(zhí)行以下兩個(gè)命令后,就可以使用數(shù)據(jù)庫(kù)了:
python manage.py makemigrations python manage.py migrate
可以調(diào)用模型管理器對(duì)象objects的相應(yīng)方法,執(zhí)行增刪改查等操作。
2)tornado
這里說(shuō)一下在tornado中使用sqlalchemy連接數(shù)據(jù)庫(kù),需要安裝sqlalchemy和pymysql。
2.2.1)首先在Config/config_db.conf中配置數(shù)據(jù)庫(kù)信息:
[db_user] name = db_tornado03 port = 3306 user = root host = 127.0.0.1 pass = test pool_size = 3
2.2.2)然后在Config/config_engine.py中配置engine:
# coding=utf-8 from sqlalchemy import create_engine from Config.config_db_get import ConfigDBUser # 數(shù)據(jù)庫(kù)配置信息 可以配置多個(gè)engine, 每個(gè)數(shù)據(jù)庫(kù)對(duì)應(yīng)一個(gè)engine db_user = ConfigDBUser("db_user") engine_user = create_engine( "mysql+pymysql://%s:%s@%s:%d/%s" % ( db_user.get_db_user(), db_user.get_db_pass(), db_user.get_db_host(), db_user.get_db_port(), db_user.get_db_database() ), encoding="utf-8", echo=True, pool_size=20, pool_recycle=100, connect_args={"charset": "utf8mb4"} )
create_engine用來(lái)初始化數(shù)據(jù)庫(kù)連接。
2.2.3)在Models/UserInfo/BaseClass.py中配置連接數(shù)據(jù)庫(kù)的session信息:
# coding=utf-8 from sqlalchemy.orm import scoped_session, sessionmaker from Config.config_engine import engine_user class BaseClass: def __init__(self): # 創(chuàng)建session對(duì)象,并且用scoped_session維護(hù)session對(duì)象 # 數(shù)據(jù)庫(kù)的增刪改查通過(guò)session對(duì)象來(lái)完成 self.engine_user = scoped_session( sessionmaker( bind=engine_user, autocommit=False, autoflush=True, expire_on_commit=False ) )
2.2.4)在Models/UserInfo/UserModel.py中配置模型信息,用于映射到數(shù)據(jù)庫(kù)中對(duì)應(yīng)的表:
# coding=utf-8 from sqlalchemy import Table, MetaData from sqlalchemy.ext.declarative import declarative_base from Config.config_engine import engine_user BaseModel = declarative_base() def user_model(table_name): class UserModel(BaseModel): __tablename__ = table_name metadata = MetaData(engine_user) Table(__tablename__, metadata, autoload=True) return UserModel
配置模型信息前,需要在數(shù)據(jù)庫(kù)中把表創(chuàng)建好,這是就需要寫sql語(yǔ)句創(chuàng)建表了。對(duì)于熟練sql的同學(xué),寫sql語(yǔ)句應(yīng)該不算什么;對(duì)應(yīng)不熟悉sql的同學(xué),可能更習(xí)慣于django中那種創(chuàng)建表的方式。
2.2.5)以上都配置好以后,就可以在視圖中使用了
App/UserInfo/views.py:
# coding=utf-8 from tornado import web from Models.UserInfo.BaseClass import BaseClass from Models.UserInfo.UserModel import user_model class UserInfoHandler(web.RequestHandler, BaseClass): def get(self): """ 獲取用戶信息 :return: """ # user_model中的參數(shù)對(duì)應(yīng)數(shù)據(jù)庫(kù)中的表名 user_info = user_model("user_info") # 獲取參數(shù) user_id = self.get_query_argument("id") # self.engine_user其實(shí)就是一個(gè)session對(duì)象;query()方法會(huì)返回一個(gè)query.Query對(duì)象,通過(guò)這個(gè)對(duì)象查詢數(shù)據(jù)庫(kù) user_info_obj = self.engine_user.query(user_info).filter(user_info.id==user_id).first() self.write(user_info_obj.name) self.finish()
2.2.6)最后配置好url:
Urls/UserInfo.py: # coding=utf-8 from App.UserInfo import views user_urls = [ (r"/userinfo", views.UserInfoHandler), ] application.py: # coding=utf-8 from tornado import web from Config.config_base import settings from Urls.UserInfo import user_urls from Urls.Shop import shop_urls """ 路由配置 """ class Application(web.Application): def __init__(self): urls = user_urls + shop_urls super(Application, self).__init__(urls, **settings)
啟動(dòng)服務(wù)后,就可以訪問(wèn)了。
3.異步非阻塞請(qǐng)求
1)django
django中可以通過(guò)celery來(lái)實(shí)現(xiàn)異步任務(wù),也可以使用asyncio和aiohttp實(shí)現(xiàn)異步。下面講一下celery的使用:
3.1.1)首先需要安裝 celery和 django-celery,使用pip安裝就行了;
3.1.2)然后在zsettings.py中進(jìn)行如下配置:
在INSTALLED_APPS中加入djcelery。 import djcelery # Celery便會(huì)去查看INSTALLD_APPS下包含的所有app目錄中的tasks.py文件,找到標(biāo)記為task的方法,將它們注冊(cè)為celery task djcelery.setup_loader() BROKER_URL = "redis://127.0.0.1:6379/2" CELERY_RESULT_BACKEND = "redis://127.0.0.1:6379/3" # 或者使用rabbitmq: BROKER_URL = "amqp://test:[email protected]:5672/testhost" CELERY_RESULT_BACKEND = "amqp://test:[email protected]:5672/testhost"
3.1.3)在需要使用異步的app中創(chuàng)建tasks.py文件,然后編輯該文件:
# coding=utf-8 import time from celery import task @task def test(data): """ 預(yù)處理 :param data: :return: """ time.sleep(3) return data
耗時(shí)的任務(wù)就可以放在使用@task修飾的函數(shù)中
3.1.4)在views.py中調(diào)用tasks.py中的函數(shù)
from rest_framework.response import Response from .tasks import test class CeleryTrainView(APIView): def get(self, request): try: for i in range(0, 5): ret = test.delay(str(i)) print("ret:", ret) except Exception as e: return Response(dict(msg=str(e), code=10001)) return Response(dict(msg="OK", code=10000))
上面的結(jié)果ret是一個(gè)AsyncResult對(duì)象,可以通過(guò)這個(gè)對(duì)象拿到保存在CELERY_RESULT_BACKEND中的結(jié)果。如果想立即得到結(jié)果,可以直接調(diào)用get()方法,但是這樣就會(huì)阻塞其他請(qǐng)求,直到結(jié)果返回:
from rest_framework.response import Response from .tasks import test class CeleryTrainView(APIView): def get(self, request): try: for i in range(0, 5): ret = test.delay(str(i)) print("ret:", ret.get()) except Exception as e: return Response(dict(msg=str(e), code=10001)) return Response(dict(msg="OK", code=10000))
3.1.5)啟動(dòng)celery
#先啟動(dòng)服務(wù)器 python manage.py runserver #再啟動(dòng)worker python manage.py celery worker
2)tornado
tornado中實(shí)現(xiàn)異步有回調(diào)和協(xié)程這兩種方式,這里只舉一個(gè)協(xié)程實(shí)現(xiàn)異步的例子:
from tornado import web from tornado import gen from tornado.httpclient import AsyncHTTPClient class AsyncHandler(web.RequestHandler): @gen.coroutine def get(self, *args, **kwargs): client = AsyncHTTPClient() url = "http://ip.taobao.com/service/getIpInfo.php?ip=14.130.112.24" # 根據(jù)ip地址獲取相關(guān)信息 resp = yield client.fetch(url) data = str(resp.body, encoding="utf-8") print("data:", data) self.write(data) self.finish()
或者像下面這樣,把獲取ip信息的部分封裝成一個(gè)函數(shù):
from tornado import web from tornado import gen from tornado.httpclient import AsyncHTTPClient class AsyncHandler(web.RequestHandler): @gen.coroutine def get(self, *args, **kwargs): ip_info = yield self.get_ip_info() self.write(ip_info) self.finish() @gen.coroutine def get_ip_info(self): client = AsyncHTTPClient() url = "http://ip.taobao.com/service/getIpInfo.php?ip=14.130.112.24" resp = yield client.fetch(url) data = str(resp.body, encoding="utf-8") return data
也可以同時(shí)發(fā)起多個(gè)異步請(qǐng)求:
from tornado import web from tornado import gen from tornado.httpclient import AsyncHTTPClient class AsyncHandler(web.RequestHandler): @gen.coroutine def get(self, *args, **kwargs): ips = [ "14.130.112.24", "14.130.112.23", "14.130.112.22" ] info1, info2, info3 = yield [self.get_ip_info(ips[0]), self.get_ip_info(ips[1]), self.get_ip_info(ips[2])] self.write(info1) self.write(info2) self.write(info3) self.finish() @gen.coroutine def get_ip_info(self, ip): client = AsyncHTTPClient() url = "http://ip.taobao.com/service/getIpInfo.php?ip=" + ip resp = yield client.fetch(url) data = str(resp.body, encoding="utf-8") return data
AsyncHTTPClient的fetch()方法有兩種調(diào)用方式,一種是像上面那樣只傳入一個(gè)url的字符串,另一種是接收一個(gè)HTTPRequest對(duì)象作為參數(shù),像下面這樣:
@gen.coroutine def get_ip_info(self, ip): client = AsyncHTTPClient() url = "http://ip.taobao.com/service/getIpInfo.php?ip=" + ip header = {"Accept": "application/json;charset=utf-8", "Content-Type": "application/x-www-form-urlencoded;charset=utf-8"} param1 = "test" http_request = HTTPRequest(url=url, method="POST", headers=header, body=urlencode({"param1": param1})) resp = yield client.fetch(http_request) data = str(resp.body, encoding="utf-8") return data
4.websocket的使用
1)django
django中使用websocket需要安裝第三方包dwebsocket。
2)tornado
tornado中實(shí)現(xiàn)websocket功能需要用到tornado.websocket模塊,主要有以下幾個(gè)方法:open(), write_message(), on_message(), on_close()
open(): 當(dāng)websocket客戶端連接時(shí)所做的操作 write_message(): 使用這個(gè)方法向客戶端發(fā)送消息 on_message(): 接收并處理客戶端的消息 on_close(): websocket關(guān)閉連接時(shí)所作的操作
下面看一個(gè)例子:
views.py: from tornado import websocket class IndexHandler(web.RequestHandler): def get(self, *args, **kwargs): self.render("chat.html") class ChatHandler(websocket.WebSocketHandler): clients = set() def open(self, *args, **kwargs): self.clients.add(self) for client in self.clients: client.write_message("%s上線了" % self.request.remote_ip) def on_message(self, message): for client in self.clients: client.write_message("%s: %s" % (self.request.remote_ip, message)) def on_close(self): self.clients.remove(self) for client in self.clients: client.write_message("%s下線了" % self.request.remote_ip) def check_origin(self, origin): """ 用于處理跨域問(wèn)題 :param origin: :return: """ return True
路由: # coding=utf-8 from App.UserInfo import views user_urls = [ (r"/index", views.IndexHandler), (r"/chat", views.ChatHandler), ]
chat.html:聊天室
上面一個(gè)例子通過(guò)websocket實(shí)現(xiàn)了簡(jiǎn)單的聊天室功能。
以上就簡(jiǎn)單的比較了django和tornado幾個(gè)方面的不同,它們各有優(yōu)缺點(diǎn),實(shí)際工作中可以根據(jù)不同的需求選擇不同的框架進(jìn)行開發(fā)。
如果想了解如何在tornado中使用tcpserver,可以看一下這篇博客:
tornado中tcpserver和tcpclient的使用
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/43233.html
摘要:前言項(xiàng)目中開發(fā)的幾個(gè)服務(wù)一直使用作為服務(wù)器,本人也曾提出過(guò)疑問(wèn),為什么是,得到的答案是比較,,,的并發(fā)性能最好,而且最為輕量級(jí)。的賣點(diǎn)是超高的開發(fā)效率,其性能擴(kuò)展有限的性能表現(xiàn)前兩天有寫一篇的帖子傳送門使用對(duì)鑒權(quán)接口加壓,看的性能表現(xiàn)。 前言 項(xiàng)目中開發(fā)的幾個(gè)服務(wù)一直使用tornado作為http服務(wù)器,本人也曾提出過(guò)疑問(wèn),為什么是tornado,得到的答案是比較tornado,fla...
摘要:項(xiàng)目地址部署的方案都在腳本里頭,說(shuō)明如下使用方法版本簡(jiǎn)單介紹是一個(gè)利用轉(zhuǎn)發(fā)操作系統(tǒng)中部署的基于框架和框架以及一個(gè)的服務(wù)。個(gè)服務(wù)是部署在環(huán)境中,通過(guò)和進(jìn)行發(fā)送和接收消息。在前臺(tái)以及整個(gè)主要利用去操作。 項(xiàng)目地址:https://github.com/yuyangit/BMProject 部署的方案都在腳本里頭,說(shuō)明如下: BMPlatform使用方法 版本 v0.2 1.簡(jiǎn)單介紹...
摘要:項(xiàng)目地址部署的方案都在腳本里頭,說(shuō)明如下使用方法版本簡(jiǎn)單介紹是一個(gè)利用轉(zhuǎn)發(fā)操作系統(tǒng)中部署的基于框架和框架以及一個(gè)的服務(wù)。個(gè)服務(wù)是部署在環(huán)境中,通過(guò)和進(jìn)行發(fā)送和接收消息。在前臺(tái)以及整個(gè)主要利用去操作。 項(xiàng)目地址:https://github.com/yuyangit/BMProject 部署的方案都在腳本里頭,說(shuō)明如下: BMPlatform使用方法 版本 v0.2 1.簡(jiǎn)單介紹...
摘要:作為網(wǎng)站的基礎(chǔ)框架,于年月日發(fā)布,目前已經(jīng)獲得了很多社區(qū)的支持,并且在一系列不同的場(chǎng)景種得到應(yīng)用。使用該框架,開發(fā)者能夠快速開發(fā)出即安全又強(qiáng)大的用戶身份認(rèn)證機(jī)制,例如機(jī)制用戶身份認(rèn)證防止跨站攻擊等等。 下一篇文章:Python:Tornado 第一章:異步及協(xié)程基礎(chǔ):第一節(jié):同步與異步I/O Tornado是一個(gè)可擴(kuò)展的非阻塞Web服務(wù)器以及相關(guān)工具的總稱。Tornado每秒可以處理...
閱讀 2084·2021-11-16 11:45
閱讀 582·2021-11-04 16:12
閱讀 1385·2021-10-08 10:22
閱讀 861·2021-09-23 11:52
閱讀 4146·2021-09-22 15:47
閱讀 3523·2021-09-22 15:07
閱讀 494·2021-09-03 10:28
閱讀 1742·2021-09-02 15:21