9-tornado-Template优化方法、个人信息案例、tornado中ORM的使用(peewee的使用、peewee_async)、WTForms的使用

在很多情况下,前端模板中在很多页面有都重复的内容可以使用,比如页头、页尾、甚至中间的内容都有可能重复。

这时,为了提高开发效率,我们就可以考虑在共同的部分提取出来,
主要方法有如下:
1. 模板继承
2. UI模板

1 模板继承

common/base.html

{% block content %}
{% end %}

shop2.html

{% extends 'common/base.html'%}

{% block content %}
{% end %}

2 UI模板

Tornado中支持累死Vue中的组件功能,就是也公共的内容提取出来当成组件。
具体的使用方式是用tornado.web.UIModule

class Entry(tornado.web.UIModule):
    def render(self, entry, show_comments=False):
        return self.render_string(
            "module-entry.html", entry=entry, show_comments=show_comments)
            
settings = {
    "Entry": Entry,
}

3 个人信息案例

环境搭建

在网站中,少了数据CRUD的操作,但在tornado中,我们知道若想操作的话尽量使用异步的操作,这样效率才会高。

那应该如何编写呢,下面我们来一起做下吧。首先我们先一起搭建下环境。

具体的操作如下:

前端

copy 原生素材

html —> templates

css —> static/css

js —> static/js

img —> static/img

到项目中

后端

from tornado import web, ioloop
from tornado.web import StaticFileHandler

class IndexHandler(web.RequestHandler):
    def get(self):
        self.render('personal.html')

import os
base_url = os.path.dirname(os.path.abspath(__file__))
settings={
    'static_path':os.path.join(base_url,'static'),
    'static_url_prefix':'/static/',
    'template_path':os.path.join(base_url,'templates')
}
if __name__ == "__main__":
    app = web.Application([
        web.URLSpec('/',IndexHandler,name='index'),
    ],
    debug=True,
    **settings
    )
    app.listen(8000)
    ioloop.IOLoop.current().start()

MySQL

CREATE TABLE `tornado_demo1`.`t_user`  (
  `id` int(10) NOT NULL,
  `username` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `nick_name` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `email` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `passsword` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `phone` varchar(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `language` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

熟悉Mysql操作

之前我们了解过pymysql操作数据库,但那是同步的。

我们需要使用一个异步的框架,在这,我们推荐使用aiomysql,它的底层大量的使用了pymysql,只是它通过asyncio实现的访问数据库

安装方式

pip install aiomysql

使用方式

import asyncio
import aiomysql

async def test_example(loop):
    pool = await aiomysql.create_pool(host='127.0.0.1', port=3306,
                                      user='root', password='root',
                                      db='mysql', loop=loop)
    async with pool.acquire() as conn:
        async with conn.cursor() as cur:
            await cur.execute("SELECT 42;")
            print(cur.description)
            (r,) = await cur.fetchone()
            assert r == 42
    pool.close()
    await pool.wait_closed()


loop = asyncio.get_event_loop()
loop.run_until_complete(test_example(loop))

4 tornado中ORM的使用

4.1 peewee的使用

官网链接

Peewee是一个简单而小型的ORM。使其易于学习且使用直观。

  • 一个小的,表达力很强的ORM
  • python 2.7+和3.4+(使用3.11开发)
  • 支持sqlite,mysql,postgresql和cockroachdb
  • 大量的扩展

安装

pip install peewee
 tip
需要安装pymysql,不然会报错

peewee.ImproperlyConfigured: MySQL driver not installed!

### 使用方式 

#### 创建表


from peewee import *

db =  MySQLDatabase('message', host="127.0.0.1", port=3306, user="root", password="root")

class BaseModel(Model):
    create_time = DateTimeField(default=datetime.now, verbose_name="添加时间")

class Music(BaseModel):
    name = CharField(index=True)
    singer = CharField(max_length=11, verbose_name="演唱者")
    duration = CharField(max_length=11, verbose_name="时长")
    _type = CharField(max_length =11,verbose_name="音乐类型")
    commany = ForeignKeyField(Commany,verbose_name="版权",backref = "musics")
    class Meta:
        database = db 
        table_name = 't_music'

class Commany(BaseModel):
    name = CharField()
    address = CharField()
    year - CharField()
db.create_tables([Cmmany,Music])

增加数据

    c = Commany()
    c.name = '中国人'
    c.full_name = '北京'
    c.year = 2003
    c.save()

    print(c.id)

    m = Music(name='中国', singer='中国1', duration='1:50',
              _type='流行', commany=c.id)
    m.save()

案例数据

    commanys = [
            {
                'name': '滚石唱片',
                'full_name': '滚石国际音乐股份有限公司',
                'year': 1980
            },
            {
                'name': '华谊兄弟',
                'full_name': '华谊兄弟传媒股份有限公司',
                'year': 1994
            },
            {
                'name': '海蝶音乐',
                'full_name': '北京太合音乐文化发展有限公司',
                'year': 1986
            },
        ]
        musics = [
            {
                "name": "你是我左边的风景",
                "singer": "林志炫",
                "duration": "2:20",
                "_type": "摇滚",
                "commany": 1
            },
            {
                "name": "把你揉碎捏成苹果",
                "singer": "薛之谦",
                "duration": "2:10",
                "_type": "摇滚",
                "commany": 3
            },
            {
                "name": "游戏人间",
                "singer": "童安格",
                "duration": "1:20",
                "_type": "流行",
                "commany": 2
            },
            {
                "name": "故乡的云",
                "singer": "费翔",
                "duration": "2:40",
                "_type": "摇滚",
                "commany": 1
            },
            {
                "name": "诺言Jason",
                "singer": "青城山下白素贞",
                "duration": "1:10",
                "_type": "古典",
                "commany": 3
            },
            {
                "name": "勇敢的幸福",
                "singer": "Sweety",
                "duration": "1:23",
                "_type": "古典",
                "commany": 2
            },
            {
                "name": "爱丫爱丫",
                "singer": "By2",
                "duration": "2:22",
                "_type": "流行",
                "commany": 1
            },
            {
                "name": "我也曾像你一样",
                "singer": "马天宇",
                "duration": "2:28",
                "_type": "流行",
                "commany": 1
            }
        ]
    
    #### 查询数据
   
    The following types of comparisons are supported by peewee:
    
    | Comparison | Meaning                                 |
    | ---------- | --------------------------------------- |
    | `==`       | x equals y                              |
    | `<`        | x is less than y                        |
    | `<=`       | x is less than or equal to y            |
    | `>`        | x is greater than y                     |
    | `>=`       | x is greater than or equal to y         |
    | `!=`       | x is not equal to y                     |
    | `<<`       | x IN y, where y is a list or query      |
    | `>>`       | x IS y, where y is None/NULL            |
    | `%`        | x LIKE y where y may contain wildcards  |
    | `**`       | x ILIKE y where y may contain wildcards |
    | `^`        | x XOR y                                 |
    | `~`        | Unary negation (e.g., NOT x)            |
    
    Because I ran out of operators to override, there are some additional query operations available as methods:
    
    | Method                | Meaning                                         |
    | --------------------- | ----------------------------------------------- |
    | `.in_(value)`         | IN lookup (identical to `<<`).                  |
    | `.not_in(value)`      | NOT IN lookup.                                  |
    | `.is_null(is_null)`   | IS NULL or IS NOT NULL. Accepts boolean param.  |
    | `.contains(substr)`   | Wild-card search for substring.                 |
    | `.startswith(prefix)` | Search for values beginning with `prefix`.      |
    | `.endswith(suffix)`   | Search for values ending with `suffix`.         |
    | `.between(low, high)` | Search for values between `low` and `high`.     |
    | `.regexp(exp)`        | Regular expression match (case-sensitive).      |
    | `.iregexp(exp)`       | Regular expression match (case-insensitive).    |
    | `.bin_and(value)`     | Binary AND.                                     |
    | `.bin_or(value)`      | Binary OR.                                      |
    | `.concat(other)`      | Concatenate two strings or objects using `||`.  |
    | `.distinct()`         | Mark column for DISTINCT selection.             |
    | `.collate(collation)` | Specify column with the given collation.        |
    | `.cast(type)`         | Cast the value of the column to the given type. |
    
    To combine clauses using logical operators, use:
    
    | Operator   | Meaning              | Example                                              |
    | ---------- | -------------------- | ---------------------------------------------------- |
    | `&`        | AND                  | `(User.is_active == True) & (User.is_admin == True)` |
    | `\|` (pipe) | OR                   | `(User.is_admin) \| (User.is_superuser)`              |
    | `~`        | NOT (unary negation) | `~(User.username.contains('admin'))`                 |
    
    Here is how you might use some of these query operators:



# Find the user whose username is "charlie".
User.select().where(User.username == 'charlie')

# Find the users whose username is in [charlie, huey, mickey]
User.select().where(User.username.in_(['charlie', 'huey', 'mickey']))

Employee.select().where(Employee.salary.between(50000, 60000))

Employee.select().where(Employee.name.startswith('C'))

Blog.select().where(Blog.title.contains(search_string))

更新数据

def update_music():
    # 方法1:获取数据,在对象上直接修改
    # m = Music.get_by_id(1)
    # m.singer='林志炫666'
    # m.save()

    # 方法2:利用类方法
    # update table set ??? where ???
    Music.update(singer='林志炫').where(Music.id == 1).execute()

删除数据

def delete_music():
    # 方法1:直接删除对象
    # m = Music.get_by_id(8)
    # m.delete_instance()

    # 方法2:利用类方法
    Music.delete().where(Music.id >5).execute()

4.2 peewee_async

peewee_async

安装

PostgreSQL

pip install --pre peewee-async
pip install aiopg

MySQL

pip install --pre peewee-async
pip install aiomysql

案例

import asyncio
import peewee
import peewee_async

# Nothing special, just define model and database:

database = peewee_async.PostgresqlDatabase(
    database='db_name',
    user='user',
    host='127.0.0.1',
    port='5432',
    password='password'
)

class TestModel(peewee.Model):
    text = peewee.CharField()

    class Meta:
        database = database

# Look, sync code is working!

TestModel.create_table(True)
TestModel.create(text="Yo, I can do it sync!")
database.close()

# Create async models manager:

objects = peewee_async.Manager(database)

# No need for sync anymore!

database.set_allow_sync(False)

async def handler():
    await objects.create(TestModel, text="Not bad. Watch this, I'm async!")
    all_objects = await objects.execute(TestModel.select())
    for obj in all_objects:
        print(obj.text)

loop = asyncio.get_event_loop()
loop.run_until_complete(handler())
loop.close()

# Clean up, can do it sync again:
with objects.allow_sync():
    TestModel.drop_table(True)

# Expected output:
# Yo, I can do it sync!
# Not bad. Watch this, I'm async!

5 WTForms的使用

简介

WTForms是用于Python Web开发的灵活的表单验证和呈现库。它可以与您选择的任何Web框架和模板引擎一起使用。

WTForms文档
WTForms_Tornado

安装

pip install wtforms-tornado

案例

import tornado.ioloop
import tornado.web

from wtforms.fields import IntegerField
from wtforms.validators import Required
from wtforms_tornado import Form

class SumForm(Form):

    a = IntegerField(validators=[Required()])
    b = IntegerField(validators=[Required()])

class SumHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

    def post(self):
        form = SumForm(self.request.arguments)
        if form.validate():
            self.write(str(form.data['a'] + form.data['b']))
        else:
            self.set_status(400)
            self.write("" % form.errors)

application = tornado.web.Application([
    (r"/", SumHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

表单验证

wftform.py

from wtforms.fields import IntegerField,StringField
from wtforms_tornado import Form
from wtforms.validators import DataRequired, Length

class UserForm(Form):
    id = IntegerField('ID')
    username  = StringField('用户名',validators=[DataRequired(message='请输入用户名'),Length(min=3,max=8,message='请输入3-8长度的用户名')])
    nick_name = StringField('昵称')
    email = StringField('Email')
    password = StringField('密码')
    phone = StringField('手机号')
    language = StringField('语言')

handler.py

forms = UserForm(self.request.arguments)
if forms.validate():
    del forms.data['id']
    await objs.create(User,**forms.data)
    self.render('personal26.html',user_form = forms)
else:
    self.render('personal26.html',user_form = forms)

HTML生成

{% autoescape None %}
	{% for field in user_form %}
   	 	{% if field.label.text == "ID"%}
	        <div class="form-group">
	            {{ field(class_="au-input au-input--full",placeholder=field.label.text)}}
	        </div>
    	{% else %}
	        <div class="form-group">
	            {{ field.label }}
	            {{ field(class_="au-input au-input--full",placeholder=field.label.text)}}
	            {% if field.errors %}
	                {{field.errors}}
	            {% end %}

	        </div>
    {% end %}                            
{% end %}
  • 18
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用`tornado_mysql`的连接池时,可以使用以下代码来执行事务: ```python import tornado.ioloop import tornado.web import tornado.gen import tornado_mysql class MainHandler(tornado.web.RequestHandler): async def get(self): db = self.application.db async with db.pool.acquire() as conn: async with conn.cursor() as cur: try: await cur.execute("START TRANSACTION") await cur.execute("INSERT INTO table_name (column1, column2) VALUES (%s, %s)", (value1, value2)) await cur.execute("UPDATE table_name SET column3 = %s WHERE id = %s", (value3, id)) await cur.execute("COMMIT") self.write("Transaction completed successfully!") except: await cur.execute("ROLLBACK") self.write("Transaction failed") class Application(tornado.web.Application): def __init__(self): handlers = [ (r"/", MainHandler), ] self.db = tornado_mysql.Pool( dict(host='localhost', port=3306, user='root', passwd='password', db='database_name'), max_size=10, autocommit=True ) super(Application, self).__init__(handlers) if __name__ == "__main__": app = Application() app.listen(8888) tornado.ioloop.IOLoop.current().start() ``` 在上述代码,我们首先创建了一个`Pool`对象,它包含了数据库的连接参数和连接池的最大连接数。然后,在我们的请求处理程序,我们通过`pool.acquire()`方法获取一个连接。我们使用`async with`来确保在完成事务后自动释放该连接。 在使用的连接上创建一个`cursor`来执行事务的SQL语句。在使用`try/except`块执行SQL语句时,如果任何一个语句失败,我们将立即回滚整个事务。如果所有语句都成功执行,则提交事务。 总之,使用`tornado_mysql`的连接池和事务非常简单,只需要在您的代码添加一些额外的异步语句即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值