Flask用户登陆系统(一)

我们的文件目录:

config.py

import os
CSRF_ENABLED = True
SECRET_KEY = 'you-will-never-guess'
basedir=os.path.abspath(os.path.dirname(__file__))
SQLALCHEMY_DATABASE_URI='sqlite:///'+os.path.join(basedir,'app.db')#数据库文件的路径
SQLALCHEMY_MIGRATE_REPO=os.path.join(basedir,'db_repository')#以后数据库存放的文件夹名称以及路径

db_create.py

#创建数据库
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
from app import db
import os.path
db.create_all()#创建数据库
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
    api.create(SQLALCHEMY_MIGRATE_REPO,'database repository')
    api.version_control(SQLALCHEMY_DATABASE_URI,SQLALCHEMY_MIGRATE_REPO)
else:
    api.version_control(SQLALCHEMY_DATABASE_URI,SQLALCHEMY_MIGRATE_REPO,api.version_control(SQLALCHEMY_MIGRATE_REPO))

db.migrate.py

#数据库迁移
import imp
from migrate.versioning import api
from app import db
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
migration = SQLALCHEMY_MIGRATE_REPO + ('/versions/%03d_migration.py' % (v+1))#数据库的路径
tmp_module = imp.new_module('old_model')
old_model = api.create_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
exec(old_model, tmp_module.__dict__)
script = api.make_update_script_for_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, tmp_module.meta, db.metadata)
open(migration, "wt").write(script)
api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)#获取当前数据库版本
print('New migration saved as ' + migration)
print('Current database version: ' + str(v))

__init__.py

import os
from flask_login import LoginManager
from config import basedir
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app=Flask(__name__)
app.config.from_object('config')
db=SQLAlchemy(app)#创建了db对象,这是我们的数据库
lm=LoginManager()
lm.init_app(app)
lm.login_view='login'#不让未登录的用户进入除了login之外的界面
from app import models,views

forms.py

from flask_wtf import FlaskForm
from wtforms import StringField,BooleanField,SubmitField,PasswordField,TextAreaField
from wtforms.validators import DataRequired,EqualTo,Email,ValidationError,Length
from .models import User
class LoginForm(FlaskForm):
    # openid=StringField('openid',validators=[DataRequired()])#Datarequired()确保字段中有数据
    remember_me=BooleanField('Remember me')
    nickname=StringField('Nickname',validators=[DataRequired()])
    password=PasswordField('Password',validators=[DataRequired()])
    submit=SubmitField('Sign in')
class RegistrationForm(FlaskForm):
    nickname=StringField('Nickname',validators=[DataRequired()])
    email=StringField('Email',validators=[DataRequired(),Email()])
    password=PasswordField('Password1',validators=[DataRequired()])
    password2=PasswordField('Repeat Password',validators=[DataRequired(),EqualTo('password')])
    def validate_nickname(self,nickname):
        user=User.query.filter_by(nickname=nickname.data).first()
        if user is not None:
            raise ValidationError('Please use a different username.')
    def validate_email(self, email):
        user = User.query.filter_by(email=email.data).first()
        if user is not None:
            raise ValidationError('Please use a different email address.') 
class EditProfileForm(FlaskForm):
    nickname = StringField('Username', validators=[DataRequired()])
    about_me = TextAreaField('About me', validators=[Length(min=0, max=140)])
    submit = SubmitField('Submit')

class LoginForm是登陆界面

RegistrationForm是注册界面

EditProfileForm是编辑个人信息

models.py

from app import db
from hashlib import md5
from datetime import datetime
class Post(db.Model):
    id=db.Column(db.Integer,primary_key=True)
    body=db.Column(db.String(140))
    timestamp=db.Column(db.DateTime)
    #author=db.Column(db.String(140))
    user_id=db.Column(db.Integer,db.ForeignKey('user.id'))

    def __repr__(self):
        return '<Post %r>'%(self.body)
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(64), index=True,unique=True,nullable=False)
    email = db.Column(db.String(120), index=True,unique=False,nullable=False)
    password=db.Column(db.String(120),index=True,unique=False,nullable=False)
    posts = db.relationship('Post', backref='author', lazy='dynamic')
    about_me=db.Column(db.String(140))
    last_seen=db.Column(db.DateTime,default=datetime.utcnow().isoformat())
    is_authenticated=True
    is_active=True
    is_anonymous=False

    def get_id(self):
        try:
            return unicode(self.id)  # python 2
        except NameError:
            return str(self.id)  # python 3
    
    def avatar(self,size):
        #return 'http://www.gravatar.com/avatar/' + md5(self.email.encode('utf-8')).hexdigest() + '?d=mm&s=' + str(size)
        digest = md5(self.email.lower().encode('utf-8')).hexdigest()
        return 'https://www.gravatar.com/avatar/{}?d=identicon&s={}'.format(
            digest, size)
    
    def check_user(self,password):#检查密码是否正确
        if self.password==password:
            return True
        else:
            return False
    def __repr__(self):
        return '<User %r>' % (self.nickname)

__repy__方法是定义打印一个User实例的格式

avatar方法是用来设置我们的头像的

hexdiges方法是用来配合md5用来使用十六进制加密的,参考

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 current_user.is_anonymous %}
    <a href="{{ url_for('login') }}">Login</a>
    {% else %}
    <a href="{{ url_for('user', nickname=current_user.nickname) }}">Profile</a>
    <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>

</html>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    {%if title%}
    <title>title--home</title>
    {%else%}
    <title>New Home</title>
    {%endif%}
</head>
<style>
    *{
        margin: 0;
        padding: 0;
    }
    body{
        height: 100%;
        width: 100%;
    }
    h1{
        height: 50px;
        width: 400px;
        margin: 100px auto;
        text-align: center;
    }
    form{
        margin: 0px auto;
        width: 300px;
        height: 300px;
    }
    form p{
        width: 250px;
        margin:15px auto;
    }
    form input{
        margin-left: 5px;
    }
</style>
<body>
    <h1>Welcome to {{title}}</h1>
    <form action="" method="post" name="login">
        {{ form.csrf_token }}
        <p class="nickname">
            Nickname:{{form.nickname}}
        </p>
        <p class="password">
            password:{{form.password}}
        </p>
        <p>{{form.remember_me.label}} {{form.remember_me()}}</p>
        <p class="signin">{{form.submit}}</p>
        <p>New User? <a href="{{ url_for('register') }}">Click to Register!</a></p>
    </form>
</body>
</html>

记得一定加上:

{{ form.csrf_token }}

register.html

{% extends "base.html" %}
{% block content %}
<h1>Register</h1>
<form action="" method="post">
    {{ form.hidden_tag() }}
    <p>
        {{ form.nickname.label }}<br>
        {{ form.nickname(size=32) }}<br>
        {% for error in form.nickname.errors %}
        <span style="color: red;">[{{ error }}]</span>
        {% endfor %}
    </p>
    <p>
        {{ form.email.label }}<br>
        {{ form.email(size=64) }}<br>
        {% for error in form.email.errors %}
        <span style="color: red;">[{{ error }}]</span>
        {% endfor %}
    </p>
    <p>
        {{ form.password.label }}<br>
        {{ form.password(size=32) }}<br>
        {% for error in form.password.errors %}
        <span style="color: red;">[{{ error }}]</span>
        {% endfor %}
    </p>
    <p>
        {{ form.password2.label }}<br>
        {{ form.password2(size=32) }}<br>
        {% for error in form.password2.errors %}
        <span style="color: red;">[{{ error }}]</span>
        {% endfor %}
    </p>
    <p>{{ form.submit() }}</p>
</form>
{% endblock %}

user.html

{% extends "base.html" %}

{% block content %}
<table>
  <tr valign="top">
    <td><img src="{{ user.avatar(128) }}"></td>
    <td>
      <h1>User: {{ user.nickname }}</h1>
      {% if user.about_me %}<p>{{ user.about_me }}</p>{% endif %}
      {% if user.last_seen %}<p>Last seen on: {{ user.last_seen }}</p>{% endif %}
      {% if user == current_user %}
      <p><a href="{{ url_for('edit_profile') }}">Edit your profile</a></p>
      {% endif %}
    </td>
  </tr>
</table>
<hr>
{% for post in posts %}
  {%include '_post.html'%}
{% endfor %}
{% endblock %}

使用了include,这是jinjia2的子模版

index.html

{% extends "base.html" %}

{% block content %}
    <h1>Hi, {{ current_user.nickname }}!</h1>
    {% for post in posts %}
    <div><p>{{ post.author.username }} says: <b>{{ post.body }}</b></p></div>
    {% endfor %}
{% endblock %}

edit_profile.html

{%extends 'base.html'%}
{% block content %}
    <h1>Edit Profile</h1>
    <form action="" method="post">
        {{ form.hidden_tag() }}
        <p>
            {{ form.nickname.label }}<br>
            {{ form.nickname(size=32) }}<br>
            {% for error in form.nickname.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>
            {{ form.about_me.label }}<br>
            {{ form.about_me(cols=50, rows=4) }}<br>
            {% for error in form.about_me.errors %}
            <span style="color: red;">[{{ error }}]</span>
            {% endfor %}
        </p>
        <p>{{ form.submit() }}</p>
    </form>
{% endblock %}

_post.html

<!-- jinjia2子模版 -->
<table>
    <tr valign="top">
        <td><img src="{{post.author.avatar(36)}}" alt=""></td>
        <td>{{post.author.nickname}}says:<br>{{post.body}}</td>
    </tr>
</table>

view.py

from flask import render_template,flash,redirect,session,url_for,request,g
from flask_login import login_user,logout_user,current_user,login_required
from app import app,db,lm
from .forms import LoginForm,RegistrationForm,EditProfileForm
from .models import User
import requests
from werkzeug.urls import url_parse
from datetime import datetime
@app.before_request
def before_request():
   if current_user.is_authenticated:
       current_user.last_seen=datetime.utcnow()
       db.session.commit()

#从数据库加载用户
@lm.user_loader
def load_user(id):
    return User.query.get(int(id))
@app.route('/')
@app.route('/index',methods=['GET','POST'])
@login_required
def index():
    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 Page",posts=posts,current_user=current_user)

#首页视图
@app.route('/login',methods=['GET','POST'])
def login():
    # print('begin login',current_user.is_authenticated)
    if current_user.is_authenticated:#如果当前的用户已经登陆
        print('is login')
        return redirect(url_for('index'))
    form=LoginForm()
    # print(form.nickname.data,form.password.data,form.remember_me.data)
    # print(User.query.filter_by(nickname="mason").first())
    if form.validate_on_submit():#form.nickname.data
        user=User.query.filter_by(nickname=form.nickname.data).first()
        if user is None or not user.check_user(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user,remember=form.remember_me.data)
        next_page=request.args.get('next')
        if not next_page or url_parse(next_page).netloc!='':
            next_page=url_for('index')
        return redirect(next_page)
    return render_template('login.html',
        title = 'Home',
        form = form)

#注册视图
@app.route('/register',methods=['GET','POST'])
def register():
    if current_user.is_authenticated:
        return redirect(url_for('index'))
    form=RegistrationForm()
    if form.validate_on_submit():
        user=User(nickname=form.nickname.data,email=form.email.data,password=form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('Congratulations, you are now a registered user!')
        return redirect(url_for('login'))
    return render_template('register.html',title="Register",form=form)
#用户信息界面
@app.route('/user/<nickname>')
@login_required
def user(nickname):
    user=User.query.filter_by(nickname=nickname).first()
    print(user)
    posts = [
        {'author': user, 'body': 'Test post #1'},
        {'author': user, 'body': 'Test post #2'}
    ]
    return render_template('user.html',user=user,posts=posts)
@app.route('/edit_profile',methods=['GET','POST'])
@login_required
def edit_profile():
    form=EditProfileForm()
    if form.validate_on_submit():
        current_user.nickname=form.nickname.data
        current_user.about_me=form.about_me.data
        db.session.commit()
        flash('Your changes have been saved.')
        return redirect(url_for('edit_profile'))
    elif request.method=='GET':#登陆后如果进入的话
        form.nickname.data=current_user.nickname
        form.about_me.data=current_user.about_me
    return render_template('edit_profile.html',title='Edit Profile',form=form)
                           

#登出视图
@app.route('/logout')
def logout():
    logout_user()
    return redirect(url_for('index'))

run.py

from app import app
app.run(debug=True)

我们就可以运行run.py了

猜你喜欢

转载自blog.csdn.net/scwMason/article/details/86764431