我们的文件目录:
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了