通过项目来深入理解tornado(四):注册功能实现
通过项目来深入理解tornado(四):注册功能实现
前言
既然短信接口已经搞定了那就来实现一下注册
另外说明一下,这个项目是类似于一个论坛的玩意,主要是写后端代码,因为现在流行前后端分离
测试接口也大部分使用requests库来进行各种请求的模拟
首先需要创建数据表
models.py
from peewee import * from tornado_bbs.models import BaseModel from bcrypt import hashpw, gensalt class PasswordHash(bytes): def check_password(self, password): password = password.encode('utf-8') return hashpw(password, self) == self class PasswordField(BlobField): def __init__(self, iterations=12, *args, **kwargs): if None in (hashpw, gensalt): raise ValueError('Missing library required for PasswordField: bcrypt') self.bcrypt_iterations = iterations self.raw_password = None super(PasswordField, self).__init__(*args, **kwargs) def db_value(self, value): """Convert the python value for storage in the database.""" if isinstance(value, PasswordHash): return bytes(value) if isinstance(value, str): value = value.encode('utf-8') salt = gensalt(self.bcrypt_iterations) return value if value is None else hashpw(value, salt) def python_value(self, value): """Convert the database value to a pythonic value.""" if isinstance(value, str): value = value.encode('utf-8') return PasswordHash(value) GENDER = ( ('female', '女'), ('male', '男') ) class User(BaseModel): mobile = CharField(max_length=11, verbose_name='手机号', index=True, unique=True) password = PasswordField(verbose_name='密码') nick_name = CharField(max_length=20, null=True, verbose_name='昵称') head_url = CharField(max_length=200, null=True, verbose_name='头像') address = CharField(max_length=200, null=True, verbose_name='地址') desc = TextField(verbose_name='描述', null=True, ) gender = CharField(max_length=6, choices=GENDER, null=True, verbose_name='性别')
这里主要是一个password字段的引入,因为在新的peewee里面,移除了password这个字段,所以需要重新翻源码来把它找回来
这里可以找回之前被删除的password字段。
然后创建表
inin_db.py
from tornado_bbs.settings import database from apps.users.models import User if __name__ == '__main__': database.create_tables([User])
这个database是在setting里的
settings.py
import peewee_async settings = { 'static_path': 'C:/Users/asd47/Desktop/tornado_bbs/static', 'template_path': 'templates', 'db':{ 'host': '127.0.0.1', 'user': 'root', 'password': 'root', 'name': 'bbs', 'port': 3306 }, 'redis':{ 'host': '127.0.0.1', } } database = peewee_async.MySQLDatabase('bbs', host='127.0.0.1', user='root', password='root', port=3306)
因为要使用协程,所以使用peewee_async来代替了peewee
然后配置url之后
就可以开始写注册的逻辑了
handler.py
import json from .models import User from tools.yun_pian import YunPian from .forms import SmsForm, RegisterForm from tornado_bbs.handler import RedisHandler from random import choice class RegisterHandler(RedisHandler): async def post(self, *args, **kwargs): params = json.loads(self.request.body.decode('utf8')) form = RegisterForm.from_json(params) re_data = {} if form.validate(): mobile = form.mobile.data code = form.code.data password = form.password.data # 验证码验证 try: code_result = int(self.redis_conn.get('{}_{}'.format(mobile, code))) except TypeError as e: code_result = '' self.set_status(400) re_data['code'] = '验证码过期' if code_result == 1: valid_code = True else: self.set_status(400) re_data['code'] = '验证码有误' valid_code = False # 验证号码是否注册 if valid_code: result = await self.application.objects.execute(User.select().where(User.mobile == mobile)) if result: self.set_status(400) re_data['mobile'] = '用户已经存在' else: await self.application.objects.create(User, mobile=mobile, password=password) self.set_status(201) else: self.set_status(400) for fields in form.errors: re_data[fields] = form.errors[fields][0] self.finish(re_data)
上面的坑集:
1.params = json.loads(self.request.body.decode('utf8'))
form = RegisterForm.from_json(params)
这里还是要用from_json,具体原因在上一章中写了。
2.查询数据库是io操作,因此需要await 但是不能直接使用peewee,因为它本身是不支持协程的
所以需要用到之前安装的peewee_async
文档里说明了,需要这样子写
objects = Manager(database) database.set_allow_sync(False) #然后把这个objects加到全局变量里 app.objects = objects
然后就有了如下的操作
await self.application.objects.execute(User.select().where(User.mobile == mobile))
await self.application.objects.create(User, mobile=mobile, password=password)
# 特别说明一下,这里execute后面的语句只是创建了一条sql语句,并没有执行,调用了execute之后才执行
# 另外,这两种方式都可以,execute里面写peewee原来的语句,或者直接用Objects的方法
至此,注册功能就完成了。
总结:
1.密码字段可以去peewee的历史记录找
2.form = RegisterForm.from_json(params),因为框架本身没处理数据,所以需要from_json方法
3.peewee_async需要额外创建Objects对象,并且设置到app里作为全局变量使用