鱼书项目模块化总结

鱼书项目模块化总结

项目总体思路

模型类

视图蓝本

表单验证数据API

flask上下文/ajax

1 异步发送邮件模块

邮件发送:

需要进行注册邮件发送或者功能模块需要发送邮件时可以采用:

from threading import Thread

from app import mail
from flask import current_app,render_template
from flask_mail import Message

‘‘‘开启异步线程‘‘‘
def send_async_mail(app,msg):
    ‘‘‘mail.send发送需要获取上下文,因此添加with‘‘‘
    with app.app_context():
        try:
            mail.send(msg)
        except Exception as e:
            raise e

def send_mail(to, subject, template,**kwargs):
    ‘‘‘
    发送邮件
    :param to: 收件人
    :param subject: 标题
    :param template: 渲染模板
    :param kwargs: 关键字参数
    :return:
    ‘‘‘
    msg = Message(‘[鱼书]‘+ ‘‘ +subject,
                  sender=current_app.config[‘MAIL_USERNAME‘],
                  recipients=[to])
    msg.html = render_template(template,**kwargs)
    ‘‘‘
    current_app是代理对象,开启新的线程时,我们直接获取真实的app核心对象_get_current_object()
    ‘‘‘
    app = current_app._get_current_object()
    thr = Thread(target=send_async_mail,args=[app,msg])
    thr.start()

2 枚举类标识状态

状态标识

状态的变更需要进行标识时(等待,成功,拒绝,撤销)

from enum import Enum

class PendingStatus(Enum):
    ‘‘‘
    交易状态: 枚举方法实现
    ‘‘‘
    Waiting = 1
    Success = 2
    Reject = 3
    Redraw = 4

    @classmethod
    def pending_str(cls,status,key):
        key_map = {
            cls.Waiting:{
                ‘requester‘:‘等待对方邮寄‘,
                ‘gifter‘:‘等待你邮寄‘
            },
            cls.Success: {
                ‘requester‘: ‘对方已邮寄‘,
                ‘gifter‘: ‘你已邮寄,交易完成‘
            },
            cls.Reject: {
                ‘requester‘: ‘对方已拒绝‘,
                ‘gifter‘: ‘你已经拒绝‘
            },
            cls.Redraw: {
                ‘requester‘: ‘你已撤销‘,
                ‘gifter‘: ‘对方已撤销‘
            }
        }
        return key_map[status][key]

3 User模型的方法

模型定义的方法:

1 password以hash方式存储

2 用户信息生成token

3 password的私有化

from math import floor

from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from itsdangerous import  TimedJSONWebSignatureSerializer as Serializer

from app.libs.enums import PendingStatus
from app.models.base import Base, db
from sqlalchemy import Column, Integer, String, Boolean, Float
from app import login_manager
from app.models.drift import Drift
from app.models.gift import Gift
from app.models.wish import Wish
from app.spider.yushu_book import YuShuBook
from app.libs.helper import is_isbn_or_key
from flask import current_app

class User(Base, UserMixin):
    ‘‘‘
    模型属性设置 , UserMixin 记录用户账号的状态
    ‘‘‘
    id = Column(Integer, primary_key=True)
    nickname = Column(String(24), nullable=False)
    _password = Column(‘password‘, String(128), nullable=True)
    phone_number = Column(String(18), unique=True)
    email = Column(String(50), unique=True, nullable=False)
    confirmed = Column(Boolean, default=False)
    beans = Column(Float, default=0)
    send_counter = Column(Integer, default=0)
    receive_counter = Column(Integer, default=0)
    wx_open_id = Column(String(50))
    wx_name = Column(String(32))

    ‘‘‘
    将password方法hash加密只读并将其变为属性访问
    ‘‘‘
    @property
    def password(self):
        return self._password

    @password.setter
    def password(self, raw):
        self._password = generate_password_hash(raw)

    def check_password(self, raw):
        return check_password_hash(self._password, raw)

    def generate_token(self, expiration=600):
        s = Serializer(current_app.config[‘SECRET_KEY‘],expiration)
        return s.dumps({‘id‘:self.id}).decode(‘utf-8‘)

    @staticmethod
    def reset_password(token,new_password):
        s = Serializer(current_app.config[‘SECRET_KEY‘])
        try:
            data = s.loads(token.encode(‘utf-8‘))
        except:
            return False
        uid = data.get(‘id‘)
        with db.auto_commit():
            user = User.query.get(uid)
            if user:
                user.password = new_password
        return True

    @property
    def summary(self):
        return dict(
            nickname = self.nickname,
            beans = self.beans,
            email = self.email,
            send_receive = str(self.send_counter)+ ‘/‘ + str(self.receive_counter)
        )

@login_manager.user_loader
def get_user(uid):
    ‘‘‘
    继承UserMixin,进行用户的回调
    :param uid:
    :return:
    ‘‘‘
    return User.query.get(int(uid))

方案二

from app.extensions import db,login_manager
from werkzeug.security import generate_password_hash,check_password_hash
#生成token的模块
from itsdangerous import TimedJSONWebSignatureSerializer as Seralize
from flask_login import UserMixin
from flask import current_app
from .posts import Posts

class User(UserMixin,db.Model):
    __tablename__ = ‘user‘
    id = db.Column(‘id‘,db.Integer,primary_key=True)
    username = db.Column(db.String(12),index=True)
    password_hash = db.Column(db.String(128))
    sex = db.Column(db.Boolean,default=True)
    age = db.Column(db.Integer)
    email = db.Column(db.String(40))
    icon = db.Column(db.String(70),default=‘default.jpg‘)
    #当期账户激活状态
    confirm = db.Column(db.Boolean,default=False)
    #参数1模型名称   参数2反向引用的字段名   参数3 加载方式 提供对象
    posts = db.relationship(‘Posts‘,backref=‘user‘,lazy=‘dynamic‘)
    #secondary在多对多关系中指定关联表的名称
    favorite = db.relationship(‘Posts‘,secondary=‘collections‘,backref=db.backref(‘users‘,lazy=‘dynamic‘),lazy=‘dynamic‘)
    #添加使用append   删除使用remove

    @property
    def password(self):
        raise ValueError

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    #生成token的方法
    def generate_token(self):
        s = Seralize(current_app.config[‘SECRET_KEY‘])
        return s.dumps({‘id‘:self.id})

    #检测token的方法
    @staticmethod
    def check_token(token):
        s = Seralize(current_app.config[‘SECRET_KEY‘])
        #从当前的token中拿出字典
        try:
            id = s.loads(token)[‘id‘]
        except:
            return False
        #根据用户id取出对应用户的对象
        u = User.query.get(id)
        #判断 当期u对象是否存在
        if not u:
            return False
        #判断当期用户的激活状态 如果没有激活 则激活
        if not u.confirm:
            u.confirm = True
            db.session.add(u)
        return True
    #验证密码
    def check_password_hash(self,password):
        return check_password_hash(self.password_hash,password)

    def is_favorite(self,postsId):
        all = self.favorite.all()
        for p in all:
            if p.id==postsId:
                return True
            #lambda表达式
            if list(filter(lambda p:p.id==int(postsId),all)):
                return True
            return False

#登录认证的回调,保持数据的一致性
@login_manager.user_loader
def user_loader(uid):
    return User.query.get(int(uid))

4 Flask工厂函数管理三方,蓝本

1 extensions.py负责三方模块的导入与

2 app.__init__.py 负责create_app初始化

3 view.__init__.py 负责蓝本的注册

方案一:

manage.py

from app import create_app
from flask_script import Manager
from flask_migrate import MigrateCommand

#通过函数create_app进行包括蓝本/扩展/系统配置的初始化
app = create_app(‘default‘)
manager = Manager(app)
#给manage添加迁移命令db
manager.add_command(‘db‘,MigrateCommand)

if __name__ == ‘__main__‘:
    manager.run()

extensions.py

#extensions.py
from flask_bootstrap import  Bootstrap
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_mail import Mail

from flask_login import LoginManager
from flask_uploads import UploadSet,IMAGES,patch_request_class,configure_uploads
from flask_moment import Moment
from flask_cache import Cache

#实例化db
db = SQLAlchemy()
#实例化bootstrap
bootstrap = Bootstrap()
#实例化migrate
migrate = Migrate(db=db)
#实例化邮箱
mail = Mail()
#实例化用户登录模块
login_manager = LoginManager()
#实例化文件对象
file = UploadSet(‘photos‘,IMAGES)
moment = Moment()
#simple简单缓存
# cache = Cache(config={‘CACHE_TYPE‘:‘simple‘})
cache = Cache(config={‘CACHE_TYPE‘: ‘simple‘})

def config_extensions(app):
    #bootstrap初始化app
    bootstrap.init_app(app)
    #db初始化app
    db.init_app(app)
    #migrate初始化app
    migrate.init_app(app=app)
    #mail初始化
    mail.init_app(app)
    #登录模块初始化
    login_manager.init_app(app)
    #moment时间模块初始化
    moment.init_app(app)
    cache.init_app(app=app)

    #需要指定登录端点
    login_manager.login_view =‘user.login‘
    #提示信息
    login_manager.login_message = ‘请登录再访问‘
    #设置session保护级别
    login_manager.session_protection = ‘strong‘

    #配置文件上传
    configure_uploads(app,file)
    patch_request_class(app,size=None)

app.__init__.py

#app.__init__.py

from flask import Flask,render_template
from app.settings import config
from app.extensions import config_extensions
from app.views import config_blueprint

#初始化当前整个应用的函数
def create_app(config_name):
    app = Flask(__name__)
    #导入settings配置信息
    app.config.from_object(config[config_name])
    #第三方库初始化
    config_extensions(app)
    #注册所有的蓝本函数
    config_blueprint(app)
    #错误页面绑定app
    errors(app)
    return app

def errors(app):
    @app.errorhandler(404)
    def page_not_found(e):
        return render_template(‘errors/error.html‘,error=e)

    @app.errorhandler(500)
    def page_not_found(e):
        return render_template(‘errors/error.html‘, error=e)

view.__init__.py

#view.__init__.py

from .main import main
from .user import user
from .posts import posts

BluePrint = [
    (main,‘‘),
    (user,‘‘),
    (posts,‘‘)
]

#封装注册蓝本的函数
def config_blueprint(app):
    #循环注册蓝本
    for blueprint,prefix in BluePrint:
        app.register_blueprint(blueprint,url_prefix=prefix)

方案二

fisher.py

from app import create_app

app = create_app()

if __name__ == ‘__main__‘:
    from werkzeug.contrib.fixers import ProxyFix
    app.wsgi_app = ProxyFix(app.wsgi_app)
    app.run()

app.__init__.py

#app.__init__.py

‘‘‘创建flask核心对象‘‘‘
from flask import Flask
from app.models.base import db
from flask_login import LoginManager
from flask_mail import Mail
from app.libs.limiter import Limiter

login_manager = LoginManager()
mail = Mail()
limiter = Limiter()

def create_app():
    ‘‘‘
    系统配置与蓝图需要绑定app
    :return:
    ‘‘‘
    app = Flask(__name__)
    app.config.from_object(‘app.secure‘)
    app.config.from_object(‘app.setting‘)
    register_blueprint(app)

    db.init_app(app)
    login_manager.init_app(app)
    login_manager.login_view = ‘web.login‘
    login_manager.login_message = ‘请先登录或者注册‘

    mail.init_app(app)
    with app.app_context():
        db.create_all()
    return app

#注册蓝本
def register_blueprint(app):
    from app.web.book import web
    app.register_blueprint(web)

view.__init__.py

#view.__init__.py

from flask import Blueprint,render_template

‘‘‘蓝图 blueprint ‘‘‘
web = Blueprint(‘web‘,__name__)  #__name__代表蓝图所在模块

@web.app_errorhandler(404)
def not_found(e):
    ‘‘‘
    AOP: 处理所有的404请求
    ‘‘‘
    return render_template(‘404.html‘),404

@web.app_errorhandler(500)
def internal_server_error(e):
    ‘‘‘
    AOP: 处理所有的500请求
    ‘‘‘
    return render_template(‘500.html‘),500

#在此处导入代表先初始化在导入应用
#防止循环调用的问题
from app.web import book
from app.web import auth
from app.web import drift
from app.web import gift
from app.web import main
from app.web import wish

5 生产开发环境下的settings配置

settings配置

1 根据不同等级,配置系统设置

2 配置数据库的连接

3 配置不同环境下的生产

方案一

import os
base_path = os.path.abspath(os.path.dirname(__file__))
#配置所有环境的基类
class Config:
    SECRET_KEY = ‘secret_key‘
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    SQLALCHEMY_TRACK_MODIFICATIONS = False

    MAIL_SERVER = os.environ.get(‘MAIL_SERVER‘, ‘smtp.163.com‘)
    MAIL_USERNAME = os.environ.get(‘MAIL_USERNAME‘, ‘[email protected]‘)
    MAIL_PASSWORD = os.environ.get(‘MAIL_PASSWORD‘, ‘xxx‘)

    #配置上传文件
    MAX_CONTENT_LENGTH = 1024*1024*64
    UPLOADED_PHOTOS_DEST = os.path.join(base_path,‘static/upload‘)

    PAGE_NUM = 3

#测试
class TestingConfig(Config):
    SQLALCHEMY_DATABASE_URI = ‘mysql+pymysql://root:[email protected]:3306/blog‘
#开发
class DevelopmentConfig(Config):
    SQLALCHEMY_DATABASE_URI = ‘mysql+pymysql://root:[email protected]:3306/blog‘
    # SQLALCHEMY_DATABASE_URI = ‘sqlite:///‘+ os.path.join(base_path,‘develop.sqlite‘)
#生产
class ProductionConfig(Config):
    SQLALCHEMY_DATABASE_URI = ‘mysql+pymysql://root:[email protected]:3306/blog‘

#设置字典
config = {
    ‘development‘:DevelopmentConfig,
    ‘production‘:ProductionConfig,
    ‘test‘:TestingConfig,
    ‘default‘:DevelopmentConfig
}

方案二

settings.py

‘‘‘
配置文件: 生产环境与开发环境相同的配置,setting可以上传git
‘‘‘
PER_PAGE = 15
BEANS_UPLOAD_ONE_BOOK = 0.5
RECENT_BOOK_COUNT = 20

secure.py

‘‘‘
配置文件:保存单独的加密信息,secure不要上传git
‘‘‘
DEBUG = True

# 单数据库
SQLALCHEMY_DATABASE_URI = ‘mysql+cymysql://root:[email protected]:3306/fisher‘
SECRET_KEY = ‘\SAAFsdfsdf:sdadzxcsd,./.dasdafasd‘

#Email相关配置
MAIL_SERVER = ‘smtp.163.com‘
MAIL_PORT = 465
MAIL_USE_SSL = True
MAIL_USE_TSL = False
MAIL_USERNAME = ‘[email protected]‘
MAIL_PASSWORD = ‘xxx‘

6 分页展示

def calulate_start(self,page):
        return (page-1)* current_app.config.get(‘PER_PAGE‘)

7 模型基类的设计

模型类的设置

1 创建基类继承db.Model

2 db实例化通过继承添加容错自动提交数据库功能

3 封装了快速设置属性功能

base.py

from flask_sqlalchemy import SQLAlchemy as _SQLAlchemy, BaseQuery
from sqlalchemy import Column, Integer, SmallInteger
from contextlib import contextmanager
from datetime import datetime

class SQLAlchemy(_SQLAlchemy):
    ‘‘‘
    封装了数据库的自动提交回滚
    ‘‘‘
    @contextmanager
    def auto_commit(self):
        try:
            yield
            self.session.commit()
        except Exception as e:
            self.session.rollback()
            raise e

class Query(BaseQuery):
    ‘‘‘
    自定义基类(继承,初始化),重写filter_by方法
    ‘‘‘
    def filter_by(self, **kwargs):
        if ‘status‘ not in kwargs.keys():
            kwargs[‘status‘] = 1
        return super(Query, self).filter_by(**kwargs)

db = SQLAlchemy(query_class=Query)

class Base(db.Model):
    ‘‘‘
    该模型表不想在数据库创建,添加__abstract__ = True不会创建该表
    ‘‘‘
    __abstract__ = True
    ‘‘‘类变量在类开始的时候就已经确定了‘‘‘
    create_time = Column(‘create_time‘, Integer)
    status = Column(SmallInteger, default=1)

    def __init__(self):
        ‘‘‘实例变量保证创建时间的准确性‘‘‘
        self.create_time = int(datetime.now().timestamp())

    def delete(self):
        self.status = 0

    def set_attrs(self, attrs_dict):
        for key, value in attrs_dict.items():
            if hasattr(self, key) and key != ‘id‘:
                setattr(self, key, value)

    @property
    def create_datetime(self):
        ‘‘‘时间格式统一,将方法转换成属性调用‘‘‘
        if self.create_time:
            return datetime.fromtimestamp(self.create_time)
        else:
            return None

原文地址:https://www.cnblogs.com/why957/p/9285838.html

时间: 2024-10-16 16:07:10

鱼书项目模块化总结的相关文章

Python Flask高级编程之从0到1开发《鱼书》精品项目 学习 教程??

Python Flask高级编程之从0到1开发<鱼书>精品项目 学习教程 一 .安装环境我们使用 flask web框架,并用 sqlalchemy来做数据库映射,并使用 migrate做数据迁移. $ pip install flask $ pip install SQLAlchemy==0.7.9 $ pip install flask-sqlalchemy $ pip install flask-migrate$ pip install sqlalchemy-migrate 二.建立项目

学习python-20191203(1)Python Flask高级编程开发鱼书_第01章 Flask的基本原理与核心知识

视频01: 做一个产品时,一定要对自己的产品有一个明确的定位.并可以用一句话来概括自己产品的核心价值或功能. 鱼书网站几个功能 1.选择要赠送的书籍,向他人赠送书籍(价值功能,核心价值的主线): 2.书籍搜索(价值辅助功能): 3.选择自己想要的书籍,向他人索要书箱(价值辅助功能). ———————————————————————————————————————————————————————————— 视频02: 一.开始flask项目的步骤: 1.安装python环境: 2.检验python

前端项目模块化的实践2:使用 Webpack 打包基础设施代码

以下是关于前端项目模块化的实践,包含以下内容: 搭建 NPM 私有仓库管理源码及依赖: 使用 Webpack 打包基础设施代码: 使用 TypeScript 编写可靠类库 (实现中) 本文是关于前端项目模板化的第2部分 现状 实际项目远远比示例使用的 myGreeting 复杂,比如 为了提高可维护性我们将项目折成了许多功能模板: 我们希望使用 Promise 等语法等,但是顾忌目标环境的支持能力: 可能依赖了多个第三方类库: 为了提高加载速度我们打包时需要进行很多额外工作: 代码压缩: Tre

Android项目模块化/组件化开发(非原创)

文章大纲 一.项目模块化初步介绍二.项目模块化的两种模式与比较三.大型项目模块化的演进四.项目模块化总结五.参考文章 一.项目模块化初步介绍 1. 前言 在Android开发中,随着项目的不断扩展,项目会变得越来越庞大,而随之带来的便是项目维护成本与开发成本的增加!每次调试时,不得不运行整个项目:每当有新成员加入团队时,需要更多的时间去了解庞大的项目...而为了解决这些问题,团队通常会将项目模块化,以此来降低项目的复杂度和耦合度,让团队可以并行开发与测试,让团队成员更加专注于自己所负责的功能模块

Python Flask高级编程之从0到1开发《鱼书》精品项目

原文地址:https://www.cnblogs.com/nobug123/p/11537546.html

iOS 使用.xcworkspace文件管理代码和工程依赖(实现项目模块化)

一.创建xcworkspace文件. 在cocoapods安装后,项目文件里都会多一个后缀为.xcworkspace的文件.打开这个文件就相当打开最初创建的项目了.那么这个文件也就是用来管理项目的,它包含你创建的项目和cocoapods的项目. 如果手动创建.xcworkspace文件怎么创建,很简单.打开Xcode 点击file  -> new -> workspace. 创建workspace 二.添加文件到.xcworkspace 创建好之后打开,现在里面没有任何工程,那就要添加工程.添

React16.4 开发简书项目 从零基础入门到实战

第1章 课程导学本章主要介绍学习react的重要性,课程的知识大纲,学习前提,讲授方式及预期收获.1-1 课程导学 第2章 React初探本章主要讲解React项目的开发环境搭建,工程代码结构及React中最基础的语法内容,同时对前端组件化思想进行介绍.2-1 React简介2-2 React开发环境准备2-3 工程目录文件简介2-4 react中的组件2-5 React 中最基础的JSX语法 第3章 React基础精讲本章通过TodoList功能的实现,给大家完整介绍React的基础语法,设计

vue 项目模块化引入百度地图

1.1.安装百度地图依赖包 npm i vue-baidu-map --save 2.在src/main.js导入依赖包 import BaiduMap from 'vue-baidu-map' Vue.use(BaiduMap, { ak: 'YOUR_APP_KEY' //这个地方是官方提供的ak密钥}) 3.配置地图的基本信息,在我们需要的组件中引用 <!--百度地图--><baidu-map class="map" :center="{lng:121

分布式架构真正适用于大型互联网项目的架构! dubbo+zookeeper+springmvc+mybatis+shiro+redis

 分类: 分布式技术(3)  目录(?)[+] 平台简介 Jeesz是一个分布式的框架,提供项目模块化.服务化.热插拔的思想,高度封装安全性的Java EE快速开发平台. Jeesz本身集成Dubbo服务管控.Zookeeper注册中心.Redis分布式缓存技术.FastDFS分布式文件系统.ActiveMQ异步消息中间件.Nginx负载均衡等分布式技术 使用Maven做项目管理,项目模块化,提高项目的易开发性.扩展性 以spring Framework为核心容器,spring MVC为模型视图