Flask学习笔记_异步论坛(四)

Flask学习笔记_异步论坛(四)

1.配置和数据库链接

1.exts.py里面实例化sqlalchemy数据库

python 复制代码
from flask_sqlalchemy import SQLAlchemy
db=SQLAlchemy()

2.config.py配置app和数据库信息

python 复制代码
#1.app配置
DEBUG=True
#2.数据库配置
DB_USERNAME="root"
DB_PASSWORD="1xxxx"
DB_HOST="127.0.0.1"
DB_PORT="3306"
DB_NAME="aforum"
DB_URI="mysql+pymysql://%s:%s@%s:%s/%s?charset=utf8mb4" % (DB_USERNAME,DB_PASSWORD,DB_HOST,DB_PORT,DB_NAME)
SQLALCHEMY_DATABASE_URI=DB_URI
SQLALCHEMY_TRACK_MODIFIER=False

3.app.py导入exts和config并初始化到app上

python 复制代码
from flask import Flask
import config
from exts import db
app=Flask(__name__)#1.实例化app
app.config.from_object(config)#2.config配置文件绑定到app
db.init_app(app)#3.数据库绑定到app
@app.route('/')
def index():
    return "hello"
if __name__=="__main__":
    app.run()

2.创建用户模型并映射到数据库

1.models/auth.py创建用户模型

python 复制代码
from exts import db
import shortuuid
from datetime import datetime
from werkzeug.security import generate_password_hash,check_password_hash


class UserModel(db.Model):
    __tablename__ = "user"
    id = db.Column(db.String(100), primary_key=True, default=shortuuid.uuid)
    email = db.Column(db.String(50), unique=True, nullable=False)
    username = db.Column(db.String(50), nullable=False)
    _password = db.Column(db.String(200), nullable=False)
    avatar = db.Column(db.String(100))
    signature = db.Column(db.String(100))
    join_time = db.Column(db.DateTime, default=datetime.now)
    is_staff = db.Column(db.Boolean, default=False)
    is_active = db.Column(db.Boolean, default=True)


    def __init__(self, *args, **kwargs):
        if "password" in kwargs:
            self.password = kwargs.get('password')
            kwargs.pop("password")
        super(UserModel, self).__init__(*args, **kwargs)

    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, newpwd):
        self._password = generate_password_hash(newpwd)
    def check_password(self,rawpwd):
        return check_password_hash(self.password, rawpwd)

2.app.py导入模型并用flask-migrate管理数据库

python 复制代码
from flask_migrate import Migrate
from models import auth
migrate=Migrate(app,db)

3.命令行migrate三部曲将模型映射到数据库

在app.py文件的目录下

python 复制代码
flask db init
flask db migrate
flask db upgrade

3.登录与注册页面的get请求

1.首先写登录和注册的前端页面

python 复制代码
#1。首先抽出base.html文件
<html>
<head>
    <meta charset="utf-8">
    <script src="http://cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
    <link href="http://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="http://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
    <script src="{{ url_for('static', filename='front/js/zlajax.js') }}"></script>
    <script src="{{ url_for('static', filename='front/js/zlparam.js') }}"></script>
    <link rel="stylesheet" href="{{ url_for('static', filename='front/css/front_base.css') }}">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{% block title %}{% endblock %}</title>
    {% block head %}{% endblock %}
</head>

<body>
    <nav class="navbar navbar-default">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="/">论坛</a>
            </div>
            <!-- Collect the nav links, forms, and other content for toggling -->
            <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                <ul class="nav navbar-nav">
                    <li class="active"><a href="/">首页<span class="sr-only">(current)</span></a></li>
                </ul>
                <form class="navbar-form navbar-left">
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="请输入关键字">
                    </div>
                    <button type="submit" class="btn btn-default">搜索</button>
                </form>
                <ul class="nav navbar-nav navbar-right">
                    {% if user %}
                      <li class="dropdown">
                          <a href="#" class="dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
                              {{ user.username }}
                              <span class="caret"></span>
                          </a>
                          <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
                              <li><a href="{{ url_for('front.cms') }}">后台管理</a></li>
                              <li><a href="{{ url_for('front.setting') }}">设置</a></li>
                              <li><a href="{{ url_for('front.logout') }}">注销</a></li>
                          </ul>
                      </li>
                    {% else %}
                      <li><a href="{{ url_for('front.login') }}">登录</a></li>
                      <li><a href="{{ url_for('front.register') }}">注册</a></li>
                    {% endif %}
                </ul>
            </div><!-- /.navbar-collapse -->
        </div><!-- /.container-fluid -->
    </nav>
    <div class="main-container">
        {% block body %}{% endblock %}
    </div>
</body>

</html>
#2.login.html文件
{% extends "front/base.html" %}

{% block title %}
  登录
{% endblock %}

{% block head %}
  <link rel="stylesheet" href="{{ url_for('static', filename='front/css/signbase.css') }}">
  <script src="{{ url_for('static', filename='front/js/login.js') }}"></script>
{% endblock %}
{% block body %}
  <div class="outer-box">
    <div class="logo-box">
      <a href="/">
        <img src="{{ url_for('static', filename='front/images/logo.png') }}" alt="">
      </a>
    </div>
    <h2 class="page-title">
      登录
    </h2>
    <div class="sign-box">
      <div class="form-group">
        <input type="text" class="form-control" name="email" placeholder="邮箱">
      </div>
      <div class="form-group">
        <input type="password" class="form-control" name="password" placeholder="密码">
      </div>
      <div class="checkbox">
        <label>
          <input type="checkbox" name="remember" value="1">记住我
        </label>
      </div>
      <div class="form-group">
        <button class="btn btn-warning btn-block" id="submit-btn">立即登录</button>
      </div>
      <div class="form-group">
        <a href="#" class="signup-link">没有账号?立即注册</a>
        <a href="#" class="resetpwd-link" style="float:right;">找回密码</a>
      </div>
    </div>
  </div>
{% endblock %}
#3.register.html文件
{% extends "front/base.html" %}

{% block title %}
  注册
{% endblock %}

{% block head %}
  <link rel="stylesheet" href="{{ url_for('static', filename='front/css/signbase.css') }}">
  <script src="{{ url_for('static', filename='front/js/register.js') }}"></script>
{% endblock %}


{% block body %}
  <div class="outer-box">
            <div class="logo-box">
                <a href="/">
                    <img src="{{ url_for('static', filename='front/images/logo.png') }}" alt="">
                </a>
            </div>
            <h2 class="page-title">
                注册
            </h2>
            <div class="sign-box">
                <div class="form-group">
                    <div class="input-group">
                        <input type="email" class="form-control" name="email" placeholder="邮箱">
                        <span class="input-group-btn">
                            <button id="email-captcha-btn" class="btn btn-default">发送验证码</button>
                        </span>
                    </div>
                </div>
                <div class="form-group">
                    <input type="text" class="form-control" name="email-captcha" placeholder="邮箱验证码">
                </div>
                <div class="form-group">
                    <input type="text" class="form-control" name="username" placeholder="用户名">
                </div>
                <div class="form-group">
                    <input type="password" class="form-control" name="password" placeholder="密码">
                </div>
                <div class="form-group">
                    <input type="password" class="form-control" name="repeat-password" placeholder="确认密码">
                </div>
                <div class="form-group">
                    <div class="input-group">
                        <input type="text" class="form-control" name="graph-captcha" placeholder="图形验证码">
                        <span class="input-group-addon captcha-addon">
                            <img id="captcha-img" class="captcha-img" src="#" alt="">
                        </span>
                    </div>
                </div>
                <div class="form-group">
                    <button class="btn btn-warning btn-block" id="submit-btn">立即注册</button>
                </div>
            </div>
        </div>
{% endblock %}

2.写它们的view蓝图并导入到__init__中

python 复制代码
#1.在apps/front/views.py里面写蓝图的视图函数
from flask import Blueprint,request,render_template
bp=Blueprint("front",__name__,url_prefix="/")

@bp.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('front/login.html')
    
@bp.route('/register/', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template('front/register.html')
#2.在apps/front/__init__.py里面导入蓝图
from .views import bp as front_bp                             

3.蓝图注册到app

python 复制代码
#在app.py里面导入蓝图并注册到app上
from apps.front import front_bp
app.register_blueprint(front_bp)

4.邮箱验证功能

1.邮箱验证

python 复制代码
#1.在config里面配置邮箱第三方服务商来发送邮件
MAIL_SERVER="smtp.qq.com"#发送验证码的邮箱服务器,这里是自己公司的邮箱服务器
MAIL_PORT='587'#587是tls协议,465是ssl协议
MAIL_USE_TLS=True
#MAIL_USE_SSL
MAIL_USERNAME="[email protected]"
MAIL_PASSWORD="wxxbe"
MAIL_DEFAULT_SENDER="[email protected]"
#2.exts里面导入mail
from flask_mail import Mail
mail=Mail()
#3.在app里面把exts里面的mail导入进来并绑定到app
from exts import db,mail
mail.init_app(app)
#4.开始在views里面写发送邮箱验证码的视图函数
from exts import mail
from flask_mail import Message
from flask importjsonify
import string,random
@bp.get("/email/captcha/")
def email_captcha():
    email=request.args.get('email')
    if not email:
        return jsonify({"code":400,"message":"请先传入邮箱"})
    source=list(string.digits)
    captcha="".join(random.sample(source,6))
    message=Message(subject="注册验证码",recipients=[email],body="您的注册验证码是:%s" % captcha)
    try:
        mail.send(message)
    except Exception as e:
        print("邮件发送失败")
        print(e)
        return jsonify({"code":500,"message":"邮件发送失败"})
    return jsonify({"code":200,"message":"邮件发送成功"})

2.使用celery异步发送邮箱验证网络请求

celery(分布式任务队列/任务调度器)和redis(内存数据库)的教程安装步骤可以参考学习。Broker和Backend都用redis存储。

pip install gevent

pip install redis

pip install hiredis

启动celery

python 复制代码
redis-cli
python 复制代码
#1.在config中设置reids的相关信息
CELERY_BROKER_URL="redis://127.0.0.1:6379/0"#broker
CELERY_RESULT_BACKEND="redis://127.0.0.1:6379/0"#backend
#2.mycelery.py里面定义并添加任务
from flask_mail import Message
from exts import mail
from celery import Celery

# 定义任务函数
def send_mail(recipient,subject,body):
  message = Message(subject=subject,recipients=[recipient],body=body)
  try:
    mail.send(message)
    return {"status": "SUCCESS"}
  except Exception :
    return {"status": "FAILURE"}

# 创建celery对象
def make_celery(app):
  celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'],broker=app.config['CELERY_BROKER_URL'])
  TaskBase = celery.Task

  class ContextTask(TaskBase):
    abstract = True

    def __call__(self, *args, **kwargs):
      with app.app_context():
        return TaskBase.__call__(self, *args, **kwargs)

  celery.Task = ContextTask
  app.celery = celery

  # 添加任务
  celery.task(name="send_mail")(send_mail)

  return celery
#3.在app.py里面将celery绑定到app
from mycelery import make_celery
mycelery=make_celery(app)
#4.在views.py里面利用current_app调用celery里面的task任务
from flask import current_app
@bp.get("/email/captcha/")
def email_captcha():
    email=request.args.get('email')
    if not email:
        return jsonify({"code":400,"message":"请先传入邮箱"})
    source=list(string.digits)
    captcha="".join(random.sample(source,6))
    subject="注册验证码"
    body="您的注册验证码是:%s"%captcha
    current_app.celery.send_task("send_mail",(email,subject,body))
    return jsonify({"code":200,"message":"邮件发送成功"})
#5.在工程目录下运行这个celery
celery -A app.mycelery worker --loglevel=info -P gevent
#6.访问这个视图函数就可以成功利用celery进行异步任务调取

3.使用flask-caching缓存验证码并验证

flask-caching的相关教程可以查看博文

python 复制代码
#1.安装:pip install flask-caching
#2.在config里面写flask-caching相关的配置
CACHE_TYPE="RedisCache"
CACHE_DEFAULT_TIMEOUT=300
CACHE_REDIS_HOST="127.0.0.1"
CACHE_REDIS_PORT=6379
#3.在exts里面引入caching
from flask_caching import Cache
cache=Cache()
#4.在app.py里面init
from exts import cache
cache.init_app(app)
#5.在view的视图函数里面缓存验证码
from exts import cache
cache.set(email,captcha)#cache缓存是键值对的形式

4.重构restful API

python 复制代码
#1.在utils/restful.py里面
# Restful API
from flask import jsonify

class HttpCode(object):
  # 响应正常
  ok = 200
  # 没有登陆错误
  unloginerror = 401
  # 没有权限错误
  permissionerror = 403
  # 客户端参数错误
  paramserror = 400
  # 服务器错误
  servererror = 500

def _restful_result(code, message, data):
  return jsonify({ "code": code,"message": message or "", "data": data or {}})

def ok(message=None, data=None):
  return _restful_result(code=HttpCode.ok, message=message, data=data)

def unlogin_error(message="没有登录!"):
  return _restful_result(code=HttpCode.unloginerror, message=message, data=None)

def permission_error(message="没有权限访问!"):
  return _restful_result(code=HttpCode.paramserror, message=message, data=None)

def params_error(message="参数错误!"):
  return _restful_result(code=HttpCode.paramserror, message=message, data=None)

def server_error(message="服务器开小差啦!"):
  return _restful_result(code=HttpCode.servererror, message=message or '服务器内部错误', data=None)
#2.在view视图函数里
from utils import restful
return restful.params_error(message="请先传入邮箱")
return restful.ok(message="邮件发送成功")

5.注册页面的post请求

5.1注册页面邮箱验证码的ajax请求

python 复制代码
#1.在register.html里面引入js文件
<script src="{{ url_for('static', filename='front/js/register.js') }}"></script>
#2.在register.js里面监听(4步),这里引用zlajax是因为它自动给了csrf-token
var RegisterHandler = function (){\\1.定义了一个JavaScript对象

}

RegisterHandler.prototype.listenSendCaptchaEvent = function (){\\2.包含一个方法
  var callback = function (event){
    // 原生的JS对象:this => jQuery对象
    var $this = $(this);
    // 阻止默认的点击事件
    event.preventDefault();
    var email = $("input[name='email']").val();
    var reg = /^\w+((.\w+)|(-\w+))@[A-Za-z0-9]+((.|-)[A-Za-z0-9]+).[A-Za-z0-9]+$/;
    if(!email || !reg.test(email)){
      alert("请输入正确格式的邮箱!");
      return;
    }
    zlajax.get({
      url: "/email/captcha?email=" + email,
      success: function (result){
        if(result['code'] == 200){
          console.log("邮件发送成功!");
          // 取消按钮的点击事件
          $this.off("click");
          // 添加禁用状态
          $this.attr("disabled", "disabled");
          // 开始倒计时
          var countdown = 60;
          var interval = setInterval(function (){
            if(countdown > 0){
              $this.text(countdown);
            }else{
              $this.text("发送验证码");
              $this.attr("disabled", false);
              $this.on("click", callback);
              // 清理定时器
              clearInterval(interval);
            }
            countdown--;
          }, 1000);
        }else{
          var message = result['message'];
          alert(message);
        }
      }
    })
  }
  $("#email-captcha-btn").on("click", callback);
}
RegisterHandler.prototype.run = function (){\\3.方法在run函数里调用
  this.listenSendCaptchaEvent();
}

// $(function(){})
$(function (){\\4.实例化并运行
  var handler = new RegisterHandler();
  handler.run();
})

#3.post请求要用csrf-token,所以在base.html里面引入
<meta name="csrf-token" content="{{csrf_token()}}">
#4.csrf-token需要先安装:
pip install flask-wtf
#5.在config里面设置secretkey
SECRET_KEY="FASDFNMLKSDF"
#6.在exts里面引入
from flask_wtf import CSRFProtect
csrf=CSRFProtect()
#6.在app上绑定init
from exts import csrf
csrf.init_app(app)

5.2注册页面的图形验证码功能

python 复制代码
#1.在config里面获取工程的base目录
import os
BASE_DIR=os.path.dirname(__file__)
#2.在utils目录下的captcha的init文件里生成图形验证码
import random
import string
# Image:一个画布
# ImageDraw:一个画笔
# ImageFont:画笔的字体
from PIL import Image,ImageDraw,ImageFont

from flask import current_app
import os

# pip install pillow

# Captcha验证码

class Captcha(object):
    # 生成几位数的验证码
    number = 4
    # 验证码图片的宽度和高度
    size = (100,30)
    # 验证码字体大小
    fontsize = 25
    # 加入干扰线的条数
    line_number = 2

    # 构建一个验证码源文本
    SOURCE = list(string.ascii_letters)
    for index in range(0, 10):
        SOURCE.append(str(index))


    #用来绘制干扰线
    @classmethod
    def __gene_line(cls,draw,width,height):
        begin = (random.randint(0, width), random.randint(0, height))
        end = (random.randint(0, width), random.randint(0, height))
        draw.line([begin, end], fill = cls.__gene_random_color(),width=2)


    # 用来绘制干扰点
    @classmethod
    def __gene_points(cls,draw,point_chance,width,height):
        chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]
        for w in range(width):
            for h in range(height):
                tmp = random.randint(0, 100)
                if tmp > 100 - chance:
                    draw.point((w, h), fill=cls.__gene_random_color())


    # 生成随机的颜色
    @classmethod
    def __gene_random_color(cls,start=0,end=255):
        random.seed()
        return (random.randint(start,end),random.randint(start,end),random.randint(start,end))


    # 随机选择一个字体
    @classmethod
    def __gene_random_font(cls):
        fonts = [
            'Courgette-Regular.ttf',
            'LHANDW.TTF',
            'Lobster-Regular.ttf',
            'verdana.ttf'
        ]
        font = random.choice(fonts)
        fontpath = os.path.join(current_app.config['BASE_DIR'],'utils','captcha',font)
        # return 'utils/captcha/'+font
        return fontpath


    # 用来随机生成一个字符串(包括英文和数字)
    @classmethod
    def gene_text(cls, number):
        # number是生成验证码的位数
        return ''.join(random.sample(cls.SOURCE, number))


    #生成验证码
    @classmethod
    def gene_graph_captcha(cls):
        # 验证码图片的宽和高
        width,height = cls.size
        # 创建图片
        # R:Red(红色)0-255
        # G:G(绿色)0-255
        # B:B(蓝色)0-255
        # A:Alpha(透明度)
        image = Image.new('RGBA',(width,height),cls.__gene_random_color(0,100))
        # 验证码的字体
        font = ImageFont.truetype(cls.__gene_random_font(),cls.fontsize)
        # 创建画笔
        draw = ImageDraw.Draw(image)
        # 生成字符串
        text = cls.gene_text(cls.number)
        # 获取字体的尺寸
        font_width, font_height = font.getsize(text)
        # 填充字符串
        draw.text(((width - font_width) / 2, (height - font_height) / 2),text,font= font,fill=cls.__gene_random_color(150,255))
        # 绘制干扰线
        for x in range(0, cls.line_number):
            cls.__gene_line(draw, width, height)
        # 绘制噪点
        cls.__gene_points(draw, 10, width, height)
        return (text,image)
#3.在views里面写视图函数
from utils.captcha import Captcha
import time
from hashlib import md5
from io import BytesIO
from flask import make_response
@bp.route("/graph/captcha/")
def graph_captcha():
    captcha,image=Captcha.gene_graph_captcha()
    key=md5((captcha+str(time.time())).encode('utf-8')).hexdigest()
    cache.set(key,captcha)#cache里面缓存这个captcha
    buffer=BytesIO()
    image.save(buffer,"png")
    buffer.seek(0)#buffer文件指针指向最开始的位置
    resp=make_response(buffer.read())
    resp.content_type="image/png"
    resp.set_cookie("_graph_captcha_key",key,max_age=3600)#将key值保存到cookie1个小时
    return resp
#4.在register.html里面写图片验证码的src
<img id="captcha-img" class="captcha-img" src="{{url_for('front.graph_captcha')}}" alt="">
#5.实现点击图片重新生成,所以在regist.js里面监听
RegisterHandler.prototype.listenGraphCaptchaEvent = function (){
  $("#captcha-img").on("click", function (){
    console.log("点击了图形验证码");
    var $this = $(this);
    var src = $this.attr("src");
    // /graph/captcha
    // /graph/captcha?sign=Math.random()
    // 防止一些老的浏览器,在两次url相同的情况下,不会重新发送请求,导致图形验证码不会更新
    let new_src = zlparam.setParam(src, "sign", Math.random())
    $this.attr("src",new_src);
  });
}
RegisterHandler.prototype.run = function (){
  this.listenSendCaptchaEvent();
  this.listenGraphCaptchaEvent();
}

5.3注册页面的post提交

python 复制代码
#1.在front/forms.py里面进行表单验证
from wtforms import Form,ValidationError
from wtforms.fields import StringField
from wtforms.validators import Email,Length,EqualTo
from models.auth import UserModel#对表单进行二次验证
from exts import cache
from flask import request
class BaseForm(Form):
    @property
    def messages(self):
        message_list = []
        if self.errors:
            for error in self.errors.values():
                message_list.extend(error)
        return message_list
class RegisterForm(BaseForm):
    email=StringField(validators=[Email(message="请输入正确的邮箱")])
    email_captcha=StringField(validators=[Length(6,6,message="请输入6位验证码")])
    username=StringField(validators=[Length(3,20,message="请输入3-20位的用户名")])
    password=StringField(validators=[Length(6,20,message="请输入6-20位的密码")])    
    repeat_password=StringField(validators=[EqualTo("password",message="两次密码不一致")])
    graph_captcha=StringField(validators=[Length(4,4,message="请输入4位图形验证码")])
    def validate_email(self,field):
        email=field.data
        user=UserModel.query.filter_by(email=email).first()
        if user:
            raise ValidationError(message="邮箱已经被注册")
    def validate_email_captcha(self,field):
        email_captcha=field.data
        email=self.email.data
        cache_captcha=cache.get(email)
        if not cache_captcha or cache_captcha!=email_captcha:
            raise ValidationError(message="邮箱验证码错误")
    def validate_graph_captcha(self,field):
        graph_captcha=field.data
        key=request.cookies.get("_graph_captcha_key")
        cache_captcha=cache.get(key)
        if not cache_captcha or cache_captcha.lower()!=graph_captcha.lower():
            raise ValidationError(message="图形验证码错误")
#2.在front/views.py里面写post视图函数
from .forms import RegisterForm
from models.auth import UserModel
from exts import db
@bp.route('/register/', methods=['GET', 'POST'])
def register():
    if request.method == 'GET':
        return render_template('front/register.html')
    else:
        form=RegisterForm(request.form)
        if form.validate():
            email=form.email.data
            username=form.username.data
            password=form.password.data
            user=UserModel(email=email,username=username,password=password)
            db.session.add(user)
            db.session.commit()
            return restful.ok()
        else:
            message=form.messages[0]
            return restful.params_error(message=message)
#3.在js里面绑定点击事件,跳到上面的视图函数
RegisterHandler.prototype.listenSubmitEvent = function (){
  $("#submit-btn").on("click", function (event){
    event.preventDefault();
    var email = $("input[name='email']").val();
    var email_captcha = $("input[name='email-captcha']").val();
    var username = $("input[name='username']").val();
    var password = $("input[name='password']").val();
    var repeat_password = $("input[name='repeat-password']").val();
    var graph_captcha = $("input[name='graph-captcha']").val();

    // 如果是商业项目,一定要先验证这些数据是否正确
    zlajax.post({
      url: "/register",
      data: {
        "email": email,
        "email_captcha": email_captcha,
        "username": username,
        password, // "password": password
        repeat_password,
        graph_captcha
      },
      success: function (result){
        if(result['code'] == 200){
          window.location = "/login";
        }else{
          alert(result['message']);
        }
      }
    })
  });
}

RegisterHandler.prototype.run = function (){
  this.listenSendCaptchaEvent();
  this.listenGraphCaptchaEvent();
  this.listenSubmitEvent();
}

6.登录页面的post请求

python 复制代码
#1.首先表单验证
from wtforms.fields import IntegerField
class LoginForm(BaseForm):
    email=StringField(validators=[Email(message="请输入正确的邮箱")])
    password=StringField(validators=[Length(6,20,message="请输入6-20位的密码")]) 
    remember=IntegerField()
#2.视图函数
from flask import session
from .forms import LoginForm
@bp.route('/login/', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        return render_template('front/login.html')
    else:
        form=LoginForm(request.form)
        if form.validate():
            email=form.email.data
            password=form.password.data
            remember=form.remember.data
            user=UserModel.query.filter_by(email=email).first()
            if not user:
                return restful.params_error("此邮箱没有注册")
            if not user.check_password(password):
                return restful.params_error("邮箱或密码错误")
            session['user_id']=user.id
            if remember ==1:
                session.permanent=True
            return restful.ok()
        else:
            return restful.params_error(message=form.messages[0])
#3.在config里面设置permanent时间
from datetime import timedelta
PERMANENT_SESSION_LIFETIME=timedelta(days=7)
#4.登录的post提交的前端监听,在login.js中,并加载到html中
var LoginHandler = function (){}

LoginHandler.prototype.listenSubmitEvent = function (){
  $("#submit-btn").on("click", function (event){
    event.preventDefault();
    var email = $("input[name='email']").val();
    var password = $("input[name='password']").val();
    var remember = $("input[name='remember']").prop("checked");
    zlajax.post({
      url: "/login",
      data: {
        email,
        password,
        remember: remember?1:0
      },
      success: function (result){
        if(result['code'] == 200){
          var token = result['data']['token'];
          var user = result['data']['user'];
          localStorage.setItem("JWT_TOKEN_KEY", token);
          localStorage.setItem("USER_KEY", JSON.stringify(user));
          window.location = "/"
        }else{
          alert(result['message']);
        }
      }
    })
  });
}

LoginHandler.prototype.run = function (){
  this.listenSubmitEvent();
}

$(function (){
  var handler = new LoginHandler();
  handler.run();
});

7.首页

相关推荐
时光追逐者10 分钟前
MongoDB从入门到实战之MongoDB快速入门(附带学习路线图)
数据库·学习·mongodb
一弓虽15 分钟前
SpringBoot 学习
java·spring boot·后端·学习
晓数1 小时前
【硬核干货】JetBrains AI Assistant 干货笔记
人工智能·笔记·jetbrains·ai assistant
我的golang之路果然有问题2 小时前
速成GO访问sql,个人笔记
经验分享·笔记·后端·sql·golang·go·database
genggeng不会代码2 小时前
用于协同显著目标检测的小组协作学习 2021 GCoNet(总结)
学习
lwewan2 小时前
26考研——存储系统(3)
c语言·笔记·考研
搞机小能手2 小时前
六个能够白嫖学习资料的网站
笔记·学习·分类
赵我说的做_life3 小时前
基于Docker的Flask项目部署完整指南
docker·容器·flask
nongcunqq3 小时前
爬虫练习 js 逆向
笔记·爬虫
汐汐咯3 小时前
终端运行java出现???
笔记