A few of the common web frameworks used in Python are Django, Tornado, Flask, etc. Today I’ll summarize the differences between Django and Tornado. Both Django and Tornado have been used in my work, and Django is more common. Personally, although Django is easy to use, it has many advantages, such as fast project setup, built-in ORM, automatic routing, built-in management background, etc. Torndo is more flexible to use and supports WebSocket, TCP, etc. Most importantly Torndo is an asynchronous non-blocking web framework. Torndo can be used as Torndo and Tornado can be used as Tornado. In order to realize websocket, asynchronous non-blocking and other functions in Django, we need to introduce DWebSocket, Celery and other third-party modules.

The environment used in this article is Python 3.6, Django 2.0, and Tornado5.1.

Here are the differences between the two frameworks in the following aspects: 1. How to create a project 2. Database connection 3. Asynchronous non-blocking requests 4. Use of WebSocket

Django creates projects mainly by using two commands:

Django-admin startpapp Test01 django-admin startpapp Test01 django-admin startpapp Test01

Upon completion, the following directory structure is generated:

D:.│ manage.py │ test-txt │ idea │ misc.xml │ modules.xml │ test-iml │ │ ├─ workspace.xml │ │ ├─ modules.xml ├─ sigma, sigma, sigma, sigma, sigma, sigma, sigma, sigma, sigma, sigma Admin.py │ apps.py │ models.py │ tests.py │ views.py │ __init__. Py │ ├ ─migrations __init__

The main files and folders are manage.py,Test, and Test01. Py is the file that manages your project and runs Django’s built-in commands, such as model migration, project startup, and so on. Test/settings.py is the configuration file where the project configuration is stored Test/urls.py is the routing file that is responsible for distributing HTTP requests Test01/models.py is the model file where the models created under Test01 are stored, The model is responsible for mapping the table structure to the database Test01/views.py is the view file where the views in Django are defined to store the migration files generated after the migration in the Test01/migrations directory. This is the basic structure of a Django project.

2) The creation of Tornado project is relatively flexible. There is no concept of project name and APP, and the project is entirely organized by oneself, which is to create a Python file and Python package. Project Tornado can be organized as follows:

├ ─ ─ App │ ├ ─ ─ just set py │ ├ ─ ─ Shop │ │ ├ ─ ─ just set py │ │ └ ─ ─ views. Py │ └ ─ ─ the User │ ├ ─ ─ just set py │ └ ─ ─ views. Py Bass Exercises ── Application. Py ─ Config │ ├─ Config_DB.py │ Bass Exercises ─ Config_DB_Get. Py │ Config_Engine ├ ─ ─ just set py ├ ─ ─ Models │ ├ ─ ─ just set py │ ├ ─ ─ Shop │ │ └ ─ ─ just set py │ └ ─ ─ the User │ ├ ─ ─ BaseClass. Py │ ├ ─ ─ Set py │ └ ─ ─ UserModel. Py ├ ─ ─ for server py ├ ─ ─ the static │ └ ─ ─ just set py ├ ─ ─ templates │ └ ─ ─ just set py ├ ─ ─ test. Py ├─ └─ Urls ├─ __init__. Py Heavy Exercises ─ Shop. Py Heavy Exercises ─ User

There are several main files: App, Config, Models, Urls, static, templates, application.py, and server.py. A project’s apps can be centrally stored in the app directory, model files corresponding to the database can be placed in Models, HTTP routes can be placed in URLs, project configuration information can be placed in the Config directory, and static files and templates can be placed in static and templates, respectively. The application.py file loads routing information and project configuration information, and the server.py file starts the project. The basic configuration information for the project can be found in Config/config_base.py, as follows:

# coding=utf-8 import OS BASE_DIR = os.path.dirname(__file__) # coding=utf-8 import OS BASE_DIR = os.path.dirname(__file__) # options = {"port": } # Settings = {"debug": True, "static_path": os.path.join(BASE_DIR, "static"), "template_path": os.path.join(BASE_DIR, "templates") }

Routing information can be placed in Urls/ user.py as follows:

# coding=utf-8


from App.UserInfo import views


user_urls = [
    (r'/user/', views.IndexHandler),
]

Load routing and configuration information in 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()

To use a database in Django, first configure the database information in settings.py:

DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql', # DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql', # DATABASES = {'default': 'django_test', # username: 'root', # PASSWORD' HOST': 'test', # HOST' PORT': '3306', # port used by database}}

Then, after you have written models.py under each app, you can use the database by executing the following two commands:

python manage.py makemigrations
python manage.py migrate

You can call the corresponding method of the model manager object objects to perform operations such as adding, deleting, modifying and checking.

2) Tornado: To connect to a database using SQLAlchemy in Tornado, you need to install SQLAlchemy and PyMySQL. 2.2.1) first configure the database information in Config/config_db.conf:

[db_user]
name = db_tornado03
port = 3306
user = root
host = 127.0.0.1
pass = test
pool_size = 3

2.2.2) then configure the engine in Config/config_engine. Py:

# coding= UTF-8 from SQLAlchemy import create_engine from config. config_db_get import ConfigDBUser # coding= UTF-8 from SQLAlchemy import create_engine from config. config_db_get import ConfigDBUser Multiple engines can be configured, 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 is used to initialize the database connection.

2.2.3) in the Models/the UserInfo/BaseClass. Connect to the database that is configured in the py session information:

# coding=utf-8 from sqlalchemy.orm import scoped_session, sessionmaker from Config.config_engine import engine_user class BaseClass: def __init__(self): Create session object; Self. Engine_user = scoped_session(sessionmaker(bind=engine_user));  autocommit=False, autoflush=True, expire_on_commit=False ) )

2.2.4) in the Models/the UserInfo/UserModel. Py configuration model of information, corresponding table used for mapping to the database:

# 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

Before configuring the model information, you need to create tables in the database. This is where you need to write SQL statements to create tables. For those of you who are proficient in SQL, writing SQL statements should be nothing. For those of you who are not familiar with SQL, you may be more accustomed to the way Django creates tables.

2.2.5) After the above is configured, you can use App/UserInfo/views.py in the view:

# 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): "" "" # user_model = user_model("user_info") # get_query_argument = self.get_query_argument("id") # Self. Engine_User is actually a session object; The query() method returns a Query.Query object, 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) Finally configure the URL:

Urls/the 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 Class Application(web.Application): def __init__(self): urls = user_urls + shop_urls super(Application, self).__init__(urls, **settings)

After you start the service, you can access it.

Asynchronous non-blocking requests 1) Django Asynchronous tasks can be implemented in Django using celery, or asyncio and AIOHttp. 3.1.1) You need to install celery and django-celery first, using PIP to install it. 3.1.2) Then do the following configuration in ZSettings.py:

Add djcelery to INSTALLED_APPS. Import djcelery # Celery will look at the tasks.py file in all the app directories included in INSTALLD_APPS and find the method marked as task. Register them as celery task djcelery.setup_loader() BROKER_URL = 'redis://127.0.0.1:6379/2' CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/3' # or use rabbitMQ: BROKER_URL = 'it: / / test: [email protected]:5672 / testhost' CELERY_RESULT_BACKEND = 'it: / / test: [email protected]:5672 / testhost'

3.1.3) Create a tasks.py file in an app that needs to use asynchrony and edit it:

# coding=utf-8 import time from celery import task@task def test(data): "" """ time.sleep(3) return data

Time-consuming tasks can then be placed in a function decorated with @Task. 3.1.4) The function in tasks.py is called in views.py

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))

The result ret is an AsyncResult object that can be used to retrieve the results stored in Celery_Result_Backend. If you want the result immediately, you can call the get() method directly, but this will block other requests until the result is returned:

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) Start Celery

Python manage.py runserver # start the worker python manage.py celery worker

2) There are two ways to realize asynchrony in Tornado: callbacks and coroutines. Here is only one example to realize asynchrony:

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' access to relevant information resp = # based on IP address yield client.fetch(url) data = str(resp.body, encoding="utf-8") print("data:", data) self.write(data) self.finish()

Or, as follows, encapsulate the part that gets the IP information as a function:

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

Multiple asynchronous requests can also be made simultaneously:

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

The AsyncHTTPClient fetch() method can be called either by passing in a single URL string, as above, or by taking an HttpRequest object as an argument, like this:

@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

To use websocket in Django, you need to install a third party package called DWebSocket.

2) Tornado.websocket module is needed to realize websocket function in Tornado.websocket, which mainly has the following methods: open(), write_message(), on_message(), on_close()

Write_message (): use this method to send a message to the client on_message(): receive and process the client message on_close(): what the websocket does when it closes the connection

Here’s an example:

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 online "% 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 offline "% self.request.remote_ip) def check_origin(self, origin): """ For handling cross-domain issues :param origin: :return: """ return True
Routing:  # coding=utf-8 from App.UserInfo import views user_urls = [ (r'/index', views.IndexHandler), (r'/chat', views.ChatHandler), ]
chat.html: <! DOCTYPE HTML > < HTML lang="en"> <head> <meta charset=" utf-8 "> <title> </head> <body> <div id="content" style="height: 500px; overflow: auto;" ></div> <div> <textarea id="msg"></textarea> <a href="javascript:;" Send the onclick = "sendMsg ()" > < / a > < / div > < script SRC = "{{static_url (' js/jquery. Min. Js)}}" > < / script > < script Type = "text/javascript" > var ws = new WebSocket (ws: / / 192.168.1.104, : 8001 / chat "); ws.onmessage = function (data) { $("#content").append("<p>"+ data.data +"</p>") }; function sendMsg() { var msg = $("#msg").val(); if (msg) { ws.send(msg); } } </script> </body> </html>

The above example implements a simple chat room functionality via WebSocket.

This is a simple comparison of the differences between Django and Tornado. Each of them has its own advantages and disadvantages. In practical work, different frameworks can be selected for development according to different needs. If you want to know how to use tcpserver in Tornado, check out this blog post: Use of tcpserver and tcpclient in Tornado