Flask 与数据库

  1. 在Linux上安装 MySQL-python,直接在终端输入sudo pip install mysql-pyhton

    1
    2
    3
    4
    5
    6
    如果出现错误::
    raise EnvironmentError("%s not found" % (mysql_config.path,))
    EnvironmentError: mysql_config not found

    原因可能是没有安装libmysqlclient-dev
    安装: sudo apt-get install libmysqlclient-dev
  2. 在Linux上安装flask-SQLAlchemy, 在终端输入sudo pip install flask-sqlalchemy

  1. 连接数据库

    • 需要提供配置:语言、驱动、用户名、密码、IP、端口、数据库名
    • 可以建立单独的配置文件config.py,内容如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      DIALECT = 'mysql'
      DRIVER = 'mysqldb'
      USERNAME = 'root'
      PASSWORD = '123'
      HOST = '127.0.0.1'
      PORT = '3306'
      DATABASE = 'pule'

      SQLALCHEMY_DATABASE_URI = "{}+{}://{}:{}@{}:{}/{}?charset=utf8".format(
      DIALECT, DRIVER, USERNAME, PASSWORD, HOST, PORT, DATABASE)

      SQLALCHEMY_TRACK_MODIFICATIONS = False
      • 为了避免model和app循环调用,我们将db部分单独分离出来,创建exts.py内容如下:

        1
        2
        from flask_sqlalchemy import SQLAlchemy
        db = SQLAlchemy()
      • 主程序中:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        # encoding=utf8
        from flask import Flask
        from exts import db
        import config

        app = Flask(__name__)
        app.config.from_object(config)
        db.init_app(app)

        @app.route('/')
        def index():
        return 'hello world'
        if __name__ == '__main__':
        app.run(debug=True)
  2. 理解ORM

    ORM 全拼Object-Relation Mapping. 中文意为对象-关系映射,主要实现模型对象到关系数据库数据的映射,比如:把数据库表中每条记录映射为一个模型对象
    创建models.py,想要创建数据库表,在此创建相应模型就好

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from exts import db

    class Article(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)
    tags = db.Column(db.String(100), nullable=False)
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    author = db.relationship('User', backref=db.backref('articles'))

    class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(100), nullable=False)

    然后在主程序中引入模型就可以使用了。from models import Article, User

  3. 数据库的增删改查

    • 查:

      1
      2
      3
      4
      5
      @app.route('/find')
      def find():
      # 查找
      result = Article.query.filter(Article.id == 4).all()
      print(result)
    • 增:

      1
      2
      3
      4
      5
      6
      @app.route('/add')
      def add():
      # 增加
      article1 = Article(title='hello world!', content='you are good man!')
      db.session.add(article1)
      db.session.commit()
    • 改:

      1
      2
      3
      4
      5
      6
      7
      @app.route('/update')
      def update():
      # 修改
      article2 = Article.query.filter(Article.id == 1).first()
      article2.title = 'new title'
      db.session.commit()
      return (str(article2.title) + ' ' + str(article2.content))
      • 删:
        1
        2
        3
        4
        5
        6
        @app.route('/remove')
        def remove():
        # 删除
        article3 = Article.query.filter(Article.id == 3).first()
        db.session.delete(article3)
        db.session.commit()
  4. 外键约束

    在这里我们有一张用户表和一张文章表,每一篇文章对应一个作者,所以将这两张表关联起来我们需要外键约束,在文章模型中我们添加这样语句:

    1
    author_id = db.Column(db.Integer, db.ForeignKey('user.id'))
  5. 一对多

    一篇作者对应多篇文章, 有时候我们需要通过文章查找这个作者, flask_sqlalchemy为我们操作提供便利:article = db.relationship('Article', backref='user', lazy='select')

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    class Article(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    tags = db.relationship('Tag', secondary=article_tag, backref='articles')
    # author = db.relationship('User', backref=db.backref('articles'))


    class User(db.Model):
    __tablename__ = 'user'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(100), nullable=False)
    articles = db.relationship('Article', backref='user', lazy='select')

    # 通过文章id去查找作者,以及作者的其他文章
    @app.route('/find_user')
    def find_user():
    article_id = 2
    article_author = Article.query.filter(Article.id == article_id).first().user
    print(article_author.username)
    print(article_author.articles[1].title)
    return article_author.username

    # 通过作者id去查找作者的所有文章
    @app.route('/find_article')
    def find_article():
    user_id = 1
    user_article = User.query.filter(User.id == user_id).first()
    return user_article.articles[0].title
  6. 多对多

    一篇文章对应多个标签, 一个标签也对应多篇文章,需要一张辅助表来保存多对多的关系

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    # 多对多关系,需要创建一张辅助表
    article_tag = db.Table('article_tag',
    db.Column('article_id', db.Integer, db.ForeignKey('article.id')),
    db.Column('tag_id', db.Integer, db.ForeignKey('tag.id'))
    )

    class Tag(db.Model):
    __tablename__ = 'tag'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(100), nullable=False)

    class Article(db.Model):
    __tablename__ = 'article'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    # 使用secondary指定多对多关系表
    tags = db.relationship('Tag', secondary=article_tag, backref='articles')
    # author = db.relationship('User', backref=db.backref('articles'))

    # 给文章存储标签
    @app.route('/add_tag')
    def add_tag():
    article_id = 1
    article = Article.query.filter(Article.id == article_id).first()
    tag = Tag.query.filter(Tag.name == 'a').first()
    article.tags.append(tag)
    db.session.commit()
    return 'ok'

    # 获取标签为’b'的所有文章
    @app.route('/get_articles')
    def get_articles():
    tag = 'c'
    articles = Tag.query.filter(Tag.name == tag).first().articles
    titles = ''
    for item in articles:
    titles = titles + item.title + ' | '
    return titles
  7. 数据库数据如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    article:
    +----+-------+------------+---------+
    | id | title | content | user_id |
    +----+-------+------------+---------+
    | 1 | one | I am one | 1 |
    | 2 | two | I am two | 2 |
    | 3 | three | I am three | 2 |
    +----+-------+------------+---------+
    user:
    +----+----------+
    | id | username |
    +----+----------+
    | 1 | 涵田 |
    | 2 | 流域 |
    | 3 | 邹文 |
    | 4 | 刘安 |
    +----+----------+
    tag:
    +----+------+
    | id | name |
    +----+------+
    | 1 | a |
    | 2 | b |
    | 3 | c |
    | 4 | d |
    | 5 | e |
    +----+------+
    article_tag:
    +------------+--------+
    | article_id | tag_id |
    +------------+--------+
    | 1 | 1 |
    | 1 | 2 |
    | 1 | 3 |
    | 2 | 3 |
    | 3 | 3 |
    | 2 | 4 |
    +------------+--------+
  8. 使用flask-script

    安装sudo pip install Flask-Script
    使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    ## 新建manager.py
    from flask_script import Manager
    manager = Manager()
    @manager.command
    def hello():
    print('hello')
    ## 或者
    from flask_script import Manager, Command
    manager = Manager()
    class Hello(Command):
    def run(self):
    print('hello')
    manager.add_command('hello', hello())
    ## 然后使用命令
    python manager.py hello
  9. 使用flask-migrate

    安装 pip install Flask-Migrate
    使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    from flask_script import Manager
    from hello import app
    from exts import db
    from flask_migrate import Migrate, MigrateCommand
    from models import Article, User

    # from db_scripts import DBmanager
    # manager.add_command('db', DBmanager)

    manager = Manager(app)
    # migrate 必须绑定app, db
    migrate = Migrate(app, db)
    # 把migrate命令传给flask——script
    manager.add_command('db', MigrateCommand)

    # 为什么要使用`migrate`,`app.create_all()`只负责映射表元素,如果数据库表新增字段或者修改字段,就必须先drop表,然后重新映射,但是drop表会清空数据,而migrate可以保证数据迁移的同时,修改或新增字段

    # 使用命令
    # 1:初始化使用,在当前目录下运行命令`python manage.py db init`
    # 2: 迁移命令`python manage.py db migrate`
    # 3: 更新数据库表 `python manage.py db upgrade`
    # 注:若使用python3执行该任务报错`python3.5/dist-packages/MySQLdb/connections.py", line 36 raise errorclass, errorvalue`,原因是`python3`不再支持mysqldb驱动,可以使用mysqlclient替代,`sudo python3 -m pip install mysqlclient`

    @manager.command
    def runserver():
    print('服务器跑起来了')
    app.run(debug=True)

    if __name__ == '__main__':
    manager.run()
  10. 开发目录结构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ├── config.py
    ├── db_scripts.py
    ├── exts.py
    ├── hello.py
    ├── manage.py
    ├── migrations
    ├── models.py
    ├── __pycache__
    ├── requirements.txt
    ├── static
    └── venv
  11. 开发依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    alembic==1.0.7
    Click==7.0
    Flask==1.0.2
    Flask-Migrate==2.4.0
    Flask-Script==2.0.6
    Flask-SQLAlchemy==2.3.2
    itsdangerous==1.1.0
    Jinja2==2.10
    Mako==1.0.7
    MarkupSafe==1.1.0
    MySQL-python==1.2.5
    mysqlclient==1.4.1
    pkg-resources==0.0.0
    PyMySQL==0.9.3
    python-dateutil==2.8.0
    python-editor==1.0.4
    six==1.12.0
    SQLAlchemy==1.2.18
    Werkzeug==0.14.1
赞 赏
微信扫一扫