-Flask开发轻博客(五):用户登录

xiaoxiao2021-02-28  25

作者:chen_h 微信号 & QQ:862251340 微信公众号:coderpai


目录

Flask开发轻博客(一):欢迎来到 Flask 的世界

Flask开发轻博客(二):Flask 模板

Flask开发轻博客(三):Flask 的 Web 表单

Flask开发轻博客(四):数据库

Flask开发轻博客(五):用户登录

Flask开发轻博客(六):用户首页和发布博客

Flask开发轻博客(七):分页


上节回顾

在上一章中,我们已经创建了数据库以及学会了使用它来存储用户以及 blog,但是我们并没有把它融入我们的应用程序中。在两章以前,我们已经看到如何创建表单并且留下了一个完全实现的登录表单。

在本章中我们将会建立 web 表单和数据库的联系,并且编写我们的登录系统。在本章结尾的时候,我们这个小型的应用程序将能够让用户能够登入和登出。

我们接下来讲述的正是我们上一章离开的地方,所以你可能要确保应用程序 micblog 正确地安装和工作。

一. 配置

像以前章节一样,我们从配置将会使用到的 Flask 扩展开始入手。对于登录系统,我们将会使用到扩展:Flask-Login。配置情况如下(文件app/__init__.py ):

from flask import Flask from flask.ext.sqlalchemy import SQLAlchemy from flask.ext.login import LoginManager # 初始化flask应用 app = Flask(__name__) app.config.from_object('config') # 初始化数据库 db = SQLAlchemy(app) # 初始化flask-Login lm = LoginManager() lm.setup_app(app) from app import views, models

二. 重构用户模型

Flask-Login 扩展需要在我们的 User 类中实现一些特定的方法。但是类如何去实现这些方法却没有什么要求。

下面就是我们为 Flask-Login 实现的 User 类(修改文件 app/models.py):

class User(db.Model): id = db.Column(db.Integer, primary_key=True) nickname = db.Column(db.String(15), index=True, unique=True) email = db.Column(db.String(128), index=True, unique=True) role = db.Column(db.SmallInteger, default=ROLE_USER) posts = db.relationship('Post', backref='author', lazy='dynamic') def is_authenticated(self): return True def is_active(self): return True def is_anonymous(self): return False def get_id(self): return unicode(self.id) @classmethod def login_check(cls, user_name): user = cls.query.filter(db.or_( User.nickname == user_name, User.email == user_name)).first() if not user: return None return user def __repr__(self): return '<User %r>' % (self.nickname)

is_authenticated 方法有一个具有迷惑性的名称。一般而言,这个方法应该只返回 True,除非表示用户的对象因为某些原因不允许被认证。

is_active 方法应该返回 True,除非是用户是无效的,比如因为他们的账号被禁止。

is_anonymous 方法应该返回 True,除非是伪造的用户不允许登录系统。

最后,get_id 方法应该返回一个用户唯一的标识符,以 unicode 格式返回我们使用数据库生成的唯一的id。

三. user_loader 回调

现在我们已经准备好用 Flask-Login 扩展来开始实现登录系统。

首先,我们必须编写一个函数用于从数据库加载用户。这个函数将会被 Flask-Login 使用(文件 app/views.py )

@lm.user_loader def load_user(user_id): return User.query.get(int(user_id))

请注意在 Flask-Login 中的用户的 id 永远是 unicode 字符串,因此在我们把id 发送给 Flask-SQLAlchemy 之前,需要把id转成整型是必须的,否则会报错!至于原因是什么就需要大家研究一下了,其实很简单的~

四. 登录视图函数

接下来我们需要更新我们的登录视图函数(文件 app/views.py )

import datetime from flask import render_template, flash, redirect, session, url_for, request, g from flask.ext.login import login_user, logout_user, current_user, login_required from models import User, Post, ROLE_USER, ROLE_ADMIN from app import app, db, lm @lm.user_loader def load_user(user_id): return User.query.get(int(user_id)) ... # 这里省略的是我们的index函数 @app.route('/login', methods=['GET', 'POST']) def login(): # 验证用户是否被验证 if current_user.is_authenticated: return redirect('index') # 注册验证 form = LoginForm() if form.validate_on_submit(): user = User.login_check(request.form.get('user_name')) if user: login_user(user) user.last_seen = datetime.datetime.now() try: db.session.add(user) db.session.commit() except: flash("The Database error!") return redirect('/login') flash('Your name: ' + request.form.get('user_name')) flash('remember me? ' + str(request.form.get('remember_me'))) return redirect(url_for("users", user_id=current_user.id)) else: flash('Login failed, Your name is not exist!') return redirect('/login') return render_template( "login.html", title="Sign In", form=form)

注意我们这里导入了不少新的模块,一些模块我们将会在不久后使用到。

整个流程就是,验证用户,验证用户是否已经注册,如果注册则从数据库中加载用户并转到用户页面。

如果要让这些都起作用的话,Flask-Login 需要知道哪个视图允许用户登录。我们在应用程序模块初始化中配置(文件 app/*init.py*)

# 初始化flask-login lm = LoginManager() lm.setup_app(app)

五. 首页视图

在前面的章节中,我们的 index 视图函数使用了伪造的对象,因为那时候我们并没有用户或者 blog。好了,现在我们有用户了,让我们使用它:

@app.route('/') @app.route('/index') def index(): user = 'Man' posts = [ { 'author': {'nickname': 'John'}, 'body': 'Beautiful day in Portland!' }, { 'author': {'nickname': 'Susan'}, 'body': 'The Avengers movie was so cool!' } ] return render_template( "index.html", title="Home", user=user, posts=posts)

这是运行应用程序最好的时候了!

六. 登出

我们已经实现了登录,现在是时候增加登出的功能。

登出的视图函数是相当地简单(文件 app/views.py )

@app.route('/logout') @login_required def logout(): logout_user() return redirect(url_for('index'))

注意,这里的 login_required 是为了验证用户必须是登陆的前提,才会有登出。

七. 注册

在注册前,我们需要修改app/forms.py文件以绑定数据库:

from flask_wtf import Form from wtforms import TextField, BooleanField, SubmitField, TextAreaField from wtforms.validators import Required, Email, Length class LoginForm(Form): user_name = TextField('user name', validators=[ Required(), Length(max=15)]) remember_me = BooleanField('remember me', default=False) submit = SubmitField('Log in') class SignUpForm(Form): user_name = TextField('user name', validators=[ Required(), Length(max=15)]) user_email = TextField('user email', validators=[ Email(), Required(), Length(max=128)]) submit = SubmitField('Sign up')

这里添加了类 SignUpForm,用户用户名和邮件的注册提交。

接下来,实现用户注册视图(文件 app/views.py ):

from forms import LoginForm, SignUpForm @app.route('/sign-up', methods=['GET', 'POST']) def sign_up(): form = SignUpForm() user = User() if form.validate_on_submit(): user_name = request.form.get('user_name') user_email = request.form.get('user_email') register_check = User.query.filter(db.or_( User.nickname == user_name, User.email == user_email)).first() if register_check: flash("error: The user's name or email already exists!") return redirect('/sign-up') if len(user_name) and len(user_email): user.nickname = user_name user.email = user_email user.role = ROLE_USER try: db.session.add(user) db.session.commit() except: flash("The Database error!") return redirect('/sign-up') flash("Sign up successful!") return redirect('/index') return render_template( "sign_up.html", form=form)

在提交注册信息的时候验证数据库中是否已经注册该用户信息,如果没有注册则在数据库中提交该信息,并显示注册成功,转到首页。

首先,修改主页(index.html):

{% extends "base.html" %} {% block content %} {% if not current_user.is_authenticated %} <h1>Hi, Guys!</h1> {% else %} <h1>Welcome back, {{ current_user.nickname }}!</h1> {% endif %} {% for post in posts %} <p>{{ post.author.nickname }} says: <b>{{ post.body }}</b></p> {% endfor %} {% endblock %}

接下来,修改登录模版(login.html):

{% extends "base.html" %} {% block content %} <h1>Sign In</h1> <form action="/login" method="post" name="login"> {{ form.hidden_tag() }} <p>Please enter your name: {{ form.user_name }}</p> {% for error in form.errors.user_name %} <p style="color:red;">[-] {{ error }}</p> {% endfor %} <p>记住我? {{ form.remember_me }}</p> <p>{{ form.submit }}</p> </form> {% endblock %}

当然,你现在如果运行程序的话,肯定会说用户名不存在,因为我们还需要建立一个注册模版(sign_up.html):

{% extends "base.html" %} {% block content %} <form action="/sign-up" method="POST" name="sign_up"> {{ form.hidden_tag() }} <p>Nick name: {{ form.user_name }}</p> {% for error in form.errors.user_name %} <p style="color:red;">[-] {{ error }}</p> {% endfor %} <p>E-mail: {{ form.user_email }}</p> {% for error in form.errors.user_email %} <p style="color:red;">[-] {{ error }}</p> {% endfor %} <p>{{ form.submit }}</p> </form> {% endblock %}

但是我们还没有在模版中添加登出和注册的链接。我们将要把这个链接放在基础层中的导航栏里(文件 app/templates/base.html )

<html> <head> {% if title %} <title>{{title}} - microblog</title> {% else %} <title>microblog</title> {% endif %} </head> <body> <div>Microblog: <a href="{{ url_for('index') }}">Home</a> {% if not current_user.is_authenticated %} | <a href="{{ url_for('login') }}">Log in</a> or <a href="{{ url_for('sign_up') }}">Sign up</a> {% else %} | <a href="{{ url_for('logout') }}">Logout</a> {% endif %} </div> <hr /> {% with messages = get_flashed_messages() %} {% if messages %} <ul> {% for message in messages %} <li>{{ message }}</li> {% endfor %} </ul> {% endif %} {% endwith %} {% block content %}{% endblock %} </body> {% block js %}{% endblock %} </html>

实现起来是不是很简单?我们已经添加了登出链接。我们也正好利用这个机会在模版中使用 url_for。

接下来,大家试试我们的注册与登陆函数吧,效果如下:

转载请注明原文地址: https://www.6miu.com/read-1450082.html

最新回复(0)