python-flask 社交博客案例

需要的模块

pip install flask

pip install  flask-login

pip install flask-sqlalchemy

pip install flask-bootstrap

程序结构

python-flask 社交博客案例_第1张图片

用户登录

1 创建虚拟环境

pipenv install

2 安装需要的模块包

pip install ……

3 根据目录结构创建目录

4 编写setting文件

import os


class BaseConfig(object):
    SECRET_KEY = os.getenv('SECRET_KEY', "key string")
    SQLALCHEMY_TRACK_MODIFICATIONS = False


class DevelopmentConfig(BaseConfig):
    SQLALCHEMY_DATABASE_URI = "mysql://root:123.com@localhost/bluelog"


class TestingConfig(BaseConfig):
    TESTING = True
    WTF_CSRF_ENABLED = False
    SQLALCHEMY_DATABASE_URI = "mysql://root:123.com@localhost/test01"


class ProductionConfig(BaseConfig):
    SQLALCHEMY_DATABASE_URI = "mysql://root:123.com@localhost/test01"



config = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'production': ProductionConfig
}

 5 编写包init文件

log_test/__init__.py

import os
import pymysql
import click
from flask import Flask
from log_test.settings import config
from log_test.extensions import db, bootstrap, login_manager
from log_test.blueprints.admin import ad
from log_test.blueprints.auth import auth
from log_test.blueprints.log import log


def create_app(config_name=None):
    if config_name is None:
        config_name = os.getenv('FLASK_CONFIG', 'development')
    app = Flask("log_test")
    app.config.from_object(config[config_name])

    register_extensions(app)
    register_blueprints(app)
    register_commands(app)

    return app


def register_extensions(app):
    pymysql.install_as_MySQLdb()
    db.init_app(app)
    bootstrap.init_app(app)
    login_manager.init_app(app)


def register_blueprints(app):
    app.register_blueprint(ad, url_prefix='/admin')
    app.register_blueprint(auth, url_prefix='/auth')
    app.register_blueprint(log)


def register_commands(app):

    from log_test.models import User, Admin

    @app.cli.command()
    @click.option('--drop', is_flag=True, help="Create drop delete")
    def initdb(drop):
        if drop:
            db.drop_all()
            click.echo("drop tables")
        db.create_all()
        click.echo("create tables")

6 引入扩展包 extensions

from flask_bootstrap import Bootstrap
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager

bootstrap = Bootstrap()
db = SQLAlchemy()
login_manager = LoginManager()


# 设置加载用户的回调函数
@login_manager.user_loader
def load_user(user_id):
    from log_test.models import Admin
    user = Admin.query.get(user_id)
    return user


# 设置登录页端点
login_manager.login_view = "auth.login"

7 编写表单 forms

from flask_wtf import FlaskForm
from wtforms import SubmitField, StringField, PasswordField, BooleanField
from wtforms.validators import DataRequired, Length, EqualTo


class LoginForm(FlaskForm):
    username = StringField("UserName", validators=[DataRequired(), Length(1, 20)])
    password = PasswordField("PassWord", validators=[DataRequired(), Length(1, 128)])
    remember = BooleanField("Remember Me")
    submit = SubmitField("Log In")


class RegistrationForm(FlaskForm):
    email = StringField("Email")
    username = StringField("UserName", validators=[DataRequired(), Length(1, 20)])
    password = PasswordField("PassWord", validators=[DataRequired(), Length(1, 128), EqualTo('password2')])
    password2 = PasswordField("Confirm PassWord", validators=[DataRequired(), Length(1, 128)])
    submit = SubmitField("Registr")

8 编写模型类 models

from werkzeug.security import generate_password_hash, check_password_hash
from log_test.extensions import db
from flask_login import UserMixin


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), unique=True)
    passwd_hash = db.Column(db.String(128))

    @property
    def passwd(self):
        raise AttributeError('not readable')

    @passwd.setter
    def passwd(self, passwd):
        self.passwd_hash = generate_password_hash(passwd)

    def verify_passwd(self, passwd):
        return check_password_hash(self.passwd_hash, passwd)


class Admin(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20))
    password_hash = db.Column(db.String(128))
    blog_title = db.Column(db.String(60))
    blog_sub_title = db.Column(db.String(100))
    name = db.Column(db.String(30))
    about = db.Column(db.Text)

    def set_password(self, password):
        self.password_hash = generate_password_hash(password)

    def validate_password(self, password):
        return check_password_hash(self.password_hash, password)


9 编写蓝图

log_test/blueprints/admin.py
--------------------------
from flask import Blueprint, render_template

ad = Blueprint("admin", __name__)


@ad.route("/")
def index():
    return render_template("admin.html")


log_test/blueprints/auth.py
------------------------
@auth.route("/", methods=('GET', 'POST'))
def login():
    form = LoginForm()
    emsg = ""
    if form.validate_on_submit():
        user_name = form.username.data
        password = form.password.data
        remember = form.remember.data
        admin = Admin.query.filter_by(username=user_name).first()
        if admin:
            if admin.validate_password(password):
                login_user(admin)
                return redirect(request.args.get('next') or url_for('log.index'))
            else:
                emsg = "密码错误"
        else:
            emsg = "账户不存在"
    return render_template("login.html", form=form, emsg=emsg)


@auth.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(url_for('auth.login'))


@auth.route("/registr", methods=('GET', 'POST'))
def registr():
    form = RegistrationForm()
    if form.validate_on_submit():
        user = Admin(username=form.username.data)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        return redirect(url_for("auth.login"))
    return render_template("registr.html", form=form)


log_test/blueprints/log.py
-----------------------
from flask import Blueprint, redirect, render_template
from flask_login import login_required, current_user

log = Blueprint("log", __name__)


@log.route('/')
@login_required
def index():
    return render_template("index.html", username=current_user.username)

10  编写templates

base.html
--------------

{% extends "bootstrap/base.html" %}

{% block title %}Flasky{% endblock %}

{% block navbar %}

{% endblock %}

{% block content %}
    {% block mycontent %}
    
    {% endblock %}
    
{% endblock %} macros.html ------------------ {% macro render_field(field) %}
{{ field.label }}:
{{ field(**kwargs)|safe }} {% if field.errors %}
    {% for error in field.errors %}
  • {{ error }}
  • {% endfor %}
{% endif %}
{% endmacro %} admin.html ------------ {% extends "base.html" %} {% block title %} Flasky {% endblock %} {% block page_content %} {% endblock %} index.html ----------- {% extends "base.html" %} {% import 'macros.html' as macros %} {% block title %} Flasky {% endblock %} {% block page_content %} {% endblock %} login.html --------------- {% extends "base.html" %} {% block title %} Flasky {% endblock %} {% import 'macros.html' as macros %} {% block page_content %}
{{ form.csrf_token }} {{ macros.render_field(form.username) }} {{ macros.render_field(form.password) }} {% if emsg %}

{{ emsg }}

{% endif %}

New user? click here to registr

{% endblock %} registr.html ---------------- {% extends "base.html" %} {% block title %} Flasky {% endblock %} {% import 'macros.html' as macros %} {% block page_content %}
{{ form.csrf_token }} {{ macros.render_field(form.username) }} {{ macros.render_field(form.password) }} {{ macros.render_field(form.password2)}} {{ macros.render_field(form.email)}} {% if emsg %}

{{ emsg }}

{% endif %}
{% endblock %}

用户角色

1 增加角色模型

models.py
-------

# 在用户模型中增加外键关联角色模型
class Admin(db.Model, UserMixin):
    
    ……
    # 定义角色外键
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    
    # 设置默认角色为User
    def __init__(self, **kwargs):
        super(Admin, self).__init__(**kwargs)
        if self.role is None:
            self.role = Role.query.filter_by(name='User').first()

    # 角色验证
    def can(self, permissions):
        return self.role is not None and (self.role.permissions & permissions) == permissions

    def is_administrator(self):
        return self.can(Permission.ADMINISTER)


# 建立角色模型
class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    default = db.Column(db.Boolean, default=False, index=True)
    permissions = db.Column(db.Integer)
    # 建立双向关系
    admins = db.relationship('Admin', backref='role', lazy='dynamic')




# 权限常量表
class Permission:
    FOLLOW = 0x01
    COMMENT = 0x02
    WRITE_ARTICLES = 0x04
    MODERATE_COMMENTS = 0x08
    ADMINISTER = 0x80



# 设置匿名用户权限验证
class AnonymousUser(AnonymousUserMixin):

    def can(self, permissions):
        return False

    def is_administrator(self):
        return False

2 自定义装饰器检查用户角色

decorators.py
------------
from functools import wraps
from flask import abort
from flask.ext.login import current_user


def permission_required(permission):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            if not current_user.can(permission):
                abort(403)
            return f(*args, **kwargs)
        return decorated_function
    return decorator

def admin_required(f):
    return permission_required(Permission.ADMINISTER)(f)

3 在数据库中创建角色

__init__.py

----------------------

def register_commands(app):

    from log_test.models import Admin, Permission, Role, Post

    ……
    @app.cli.command()
    def initroles():
        roles = {
            'User': (Permission.FOLLOW | Permission.COMMENT | Permission.WRITE_ARTICLES, True),
            'Moderator': (Permission.FOLLOW | Permission.COMMENT | Permission.WRITE_ARTICLES | Permission.MODERATE_COMMENTS, False),
            'Administor': (0xff, False)
        }
        for r in roles:
            role = Role.query.filter_by(name=r).first()
            if role is None:
                role = Role(name=r)
            role.permissions = roles[r][0]
            role.default = roles[r][1]
            db.session.add(role)
        db.session.commit()


flask initdb --drop 重新创建数据库

flask initroles 初始化角色

4  测试

admin.py
-------

from flask import Blueprint, render_template, request, redirect, url_for
from flask_login import login_required, current_user
from log_test.utols import admin_required, permission_required
from log_test.models import Permission


ad = Blueprint("admin", __name__)


@ad.route('/')
@login_required
@admin_required
def for_admins_only():
    return "For administrators!"


@ad.route('/moderator')
@login_required
@permission_required(Permission.MODERATE_COMMENTS)
def for_moderators_only():
    return "For comment moderators!"


# 把 Permission 类加入模板上下文
@ad.app_context_processor
def inject_permissions():
    return dict(Permission=Permission)

5 测试前记得先给用户配置好权限

分页

1 查询出结果

@log.route('/', methods=('GET', 'POST'))
@login_required
def index():
    form = PostForm()

    if form.validate_on_submit():
        post = Post(body=form.body.data,
                    admin=current_user._get_current_object())
        db.session.add(post)
        db.session.commit()
        return redirect(url_for("log.index"))
    page = request.args.get('page', 1, type=int)
    #  paginate() 分页函数: page 页码、 per_page 可选参数默认20,error_out 默认True 超出页面范围返回404错误,false 超出页面范围返回空列表
    pagination = Post.query.order_by(Post.timestamp.desc()).paginate(page, per_page=current_app.config['FLASKY_POSTS_PER_PAGE'], error_out=False)
    # 返回当前页中内容
    posts = pagination.items
    return render_template("index.html", form=form, posts=posts, pagination=pagination)
    # return render_template("index.html", form=form, posts=posts)

2 编写分页宏模版

macros.html
-----------

{% macro pagination_widget(pagination, endpoint) %}
  • «
  • {% for p in pagination.iter_pages() %} {% if p %} {% if p == pagination.page %}
  • {{ p }}
  • {% else %}
  • {{ p }}
  • {% endif %} {% else %}
  • {% endif %} {% endfor %}
  • »
{% endmacro %}

3 引入宏

index.html
---------------



{% import 'macros.html' as macros %}


…………



{% endblock %}

python-flask 社交博客案例_第2张图片

 

你可能感兴趣的:(python,python,flask,后端)