【Flask】cookiecutter-flask生成的database.py代码分析

关于cookiecutter-flask

Cookiecutter可以让你快速从模板中建立工程,cookiecutter-flask则是Flask的模板,可以快速生成Flask大型项目模板。

cookiecutter-flask生成的工程目录下有一个database.py文件,主要是对数据表功能的一个扩展。这篇文章是对这份代码简单分析。上代码

database.py

# -*- coding: utf-8 -*-
"""Database module, including the SQLAlchemy database object and DB-related
utilities.
"""
from sqlalchemy.orm import relationship

from .extensions import db
from .compat import basestring

# Alias common SQLAlchemy names
Column = db.Column
relationship = relationship


class CRUDMixin(object):
    """Mixin that adds convenience methods for CRUD (create, read, update, delete)
    operations.
    """

    @classmethod
    def create(cls, **kwargs):
        """Create a new record and save it the database."""
        instance = cls(**kwargs)
        return instance.save()

    def update(self, commit=True, **kwargs):
        """Update specific fields of a record."""
        for attr, value in kwargs.iteritems():
            setattr(self, attr, value)
        return commit and self.save() or self

    def save(self, commit=True):
        """Save the record."""
        db.session.add(self)
        if commit:
            db.session.commit()
        return self

    def delete(self, commit=True):
        """Remove the record from the database."""
        db.session.delete(self)
        return commit and db.session.commit()

class Model(CRUDMixin, db.Model):
    """Base model class that includes CRUD convenience methods."""
    __abstract__ = True


# From Mike Bayer's "Building the app" talk
# https://speakerdeck.com/zzzeek/building-the-app
class SurrogatePK(object):
    """A mixin that adds a surrogate integer 'primary key' column named
    ``id`` to any declarative-mapped class.
    """
    __table_args__ = {'extend_existing': True}

    id = db.Column(db.Integer, primary_key=True)

    @classmethod
    def get_by_id(cls, id):
        if any(
            (isinstance(id, basestring) and id.isdigit(),
             isinstance(id, (int, float))),
        ):
            return cls.query.get(int(id))
        return None


def ReferenceCol(tablename, nullable=False, pk_name='id', **kwargs):
    """Column that adds primary key foreign key reference.

    Usage: ::

        category_id = ReferenceCol('category')
        category = relationship('Category', backref='categories')
    """
    return db.Column(
        db.ForeignKey("{0}.{1}".format(tablename, pk_name)),
        nullable=nullable, **kwargs)

CRUDMixin拥有四个方法,分别是createupdatesavedelete。可以让数据表对象一步操作CURD。

Model分别继承CRUDMixin和SQLAchemy的db.Model,后面的数据表对象只需要继承Model就同时继承了CRUDMixin方法了。

SurrogatePK是为数据表添加主键字段。继承SurrogatePK即可。

ReferenceCol是外键引用,封装了db.ForeignKey的操作。

数据表

下面放上User和Role的数据表,该User和Role是一对多关系。

class User(UserMixin, SurrogatePK, Model):

    __tablename__ = 'users'
    username = Column(db.String(80), unique=True, nullable=False)
    email = Column(db.String(80), unique=True, nullable=False)
    #: The hashed password
    password = Column(db.String(128), nullable=True)
    created_at = Column(db.DateTime, nullable=False, default=dt.datetime.utcnow)
    first_name = Column(db.String(30), nullable=True)
    last_name = Column(db.String(30), nullable=True)
    active = Column(db.Boolean(), default=False)
    is_admin = Column(db.Boolean(), default=False)

    def __init__(self, username, email, password=None, **kwargs):
        db.Model.__init__(self, username=username, email=email, **kwargs)
        if password:
            self.set_password(password)
        else:
            self.password = None

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

    def check_password(self, value):
        return bcrypt.check_password_hash(self.password, value)

    @property
    def full_name(self):
        return "{0} {1}".format(self.first_name, self.last_name)

    def __repr__(self):
        return '<User({username!r})>'.format(username=self.username)

class Role(SurrogatePK, Model):
    __tablename__ = 'roles'
    name = Column(db.String(80), unique=True, nullable=False)
    user_id = ReferenceCol('users', nullable=True)
    user = relationship('User', backref='roles')

    def __init__(self, name, **kwargs):
        db.Model.__init__(self, name=name, **kwargs)

    def __repr__(self):
        return '<Role({name})>'.format(name=self.name)

另外注意一点的是,要使数据表支持Flask-Admin,需要把__init__的参数设一个默认值。比如USER的
def __init__(self, username, email, password=None, **kwargs)
要修改为
def __init__(self, username="", email="", password=None, **kwargs)

否则Flask-Admin编辑时会报错。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的内容,你在运行flask db init命令时遇到了错误。错误信息显示找不到Flask应用程序或工厂模块"app",这可能是因为你的项目中没有找到app.py文件。解决方案是将manage.py重命名为app.py,然后使用set FLASK_APP=manage.py flask db init命令来指定Flask应用程序。这样应该能够解决问题。 另外,根据引用\[3\]的内容,你在运行flask db migrate命令时也遇到了错误。错误信息显示SQLALCHEMY_DATABASE_URI和SQLALCHEMY_TRACK_MODIFICATIONS配置错误。你可以尝试在配置文件中正确设置SQLALCHEMY_DATABASE_URI和SQLALCHEMY_TRACK_MODIFICATIONS参数,以解决这个问题。 至于你提到的问题"Could not import '02_flask'",根据提供的信息,无法确定具体的原因。可能是由于文件路径或导入模块的问题导致的。你可以检查文件路径是否正确,并确保你的代码中正确导入了'02_flask'模块。 希望以上解答对你有帮助。如果还有其他问题,请随时提问。 #### 引用[.reference_title] - *1* *3* [flask 运行 flask db init 报错,init-db 命令找不到](https://blog.csdn.net/weixin_42290927/article/details/87283829)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Error: Could not locate a Flask application. You did not provide the “FLASK_APP“ environment ...](https://blog.csdn.net/weixin_48368715/article/details/122289784)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值