通过项目来深入理解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这个字段,所以需要重新翻源码来把它找回来

https://github.com/coleifer/peewee/commit/04979500366d4b8b31694eb629d7ea28f05c58c4#diff-56fcfb44764a22a2dcd8613a4d6e50a6

这里可以找回之前被删除的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里作为全局变量使用

 

posted @ 2018-11-26 16:11  __Miracle  阅读(648)  评论(0编辑  收藏  举报