美文网首页
2020-06-13--flask07--flask基础07

2020-06-13--flask07--flask基础07

作者: program_white | 来源:发表于2020-06-14 21:33 被阅读0次
    • 关联查询
    • 图书作者案例

    1.项目基本结构
    2.数据库
    3.插入数据的表单类
    4.编写作者,书籍的展示和添加
    5.删除作者,删除书籍

    关联查询

    model层的表中存在一对一,一对多,多对多三种关系,其中一对多关系最为常见。
    上一章中使用的一些查询都是单表查询,只是在一个表中根据某个字段进行查询,那么怎么快速的多表查询呢?

    relationship函数是sqlalchemy对关系之间提供的一种便利的调用方式
    backref:参数则对关系提供反向引用的声明。

    实例:

    #角色类
    class Role(db.Model):
        #定义表名
        __tablename__ = 'role'
        #id
        id = db.Column(db.Integer,primary_key=True)
        #name
        name = db.Column(db.String(64),unique=True)
        user = db.relationship('User',backref = 'role')        #用于查询一对多 role.user
    
    #用户类
    class User(db.Model):
        __tablename__ = 'user'
        id = db.Column(db.Integer,primary_key=True)
        name = db.Column(db.String(64),unique=True)
        email = db.Column(db.String(64),unique=True)
        password = db.Column(db.String(64))
        role_id = db.Column(db.Integer,db.ForeignKey('role.id'))        #正向关联外键,role_id与role表中的id关联
    

    详解:

    realtionship函数定义在主表上。
    realtionship描述了模型类Role类User类的关系。在此文中

    • 第一个参数为对应参照的类"User"(附表类名)
    • 第二个参数backref为类User申明新属性role,也就是说当要用User类查询Role类中的数据时,可以直接调用 ----------- User类对象(user1).role,获取该用户所扮演的角色。
    • 第三个参数lazy决定了什么时候SQLALchemy从数据库中加载数据
      如果设置为子查询方式(subquery),则会在加载完Role对象后,就立即加载与其关联的对象,这样会让总查询数量减少,但如果返回的条目数量很多,就会比较慢
      *设置为 subquery 的话,role.users 返回所有数据列表
      *另外,也可以设置为动态方式(dynamic),这样关联对象会在被使用的时候再进行加载,并且在返回前进行过滤,如果返回的对象数很多,或者未来会变得很多,那最好采用这种方式
      *设置为 dynamic 的话,role.users 返回查询对象,并没有做真正的查询,可以利用查询对象做其他逻辑,比如:先排序再返回结果

    参数详解:



    上图错误:relationship('附表类名',backref = '用于快速多查一时调用')

    图书作者案例

    功能展示:
    如果作者存在,书籍存在,不能添加
    如果作者存在,书籍不存在,可以添加
    如果作者不存在,书籍存在,可以添加
    如果作者不存在,书籍不存在,可以添加

    1. 删除书籍
    2. 删除作者,同时删除作者所有的书籍
    3. 使用wtf表单完成

    1.项目基本结构

    创建项目基本结构demo_library.py:

    from flask import Flask, render_template
    from flask_sqlalchemy import SQLAlchemy
    
    app = Flask(__name__)
    
    @app.route('/')
    def index():
        return render_template('library.html')
    
    if __name__ == '__main__':
        app.run(debug=True)
    

    2.数据库

    • 设置数据库
    • 数据库基配置
    • 编写model类
    • 创建表
    • 添加测试数据
    from flask_sqlalchemy import SQLAlchemy
    
    '''数据库'''
    host = 'localhost'
    port = '3306'
    useranme = 'root'
    password = 'root'
    db = 'library'
    
    mysqlpath = 'mysql+pymysql://{}:{}@{}:{}/{}'.format(useranme,password,host,port,db)
    app.config['SQLALCHEMY_DATABASE_URI'] = mysqlpath
    db = SQLAlchemy(app)
    
    '''数据库相关设置'''
    # 设置每次请求后自动提交数据库的改动
    app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] =True
    # 动态追踪设置
    app.config['SQLALCHEMY_TRACK_MODUFICATIONS'] = True
    # 显示原始sql
    app.config['SQLALCHEMY_ECHO'] = True
    
    
    '''model类'''
    class Auther(db.Model):
        __tablename__ = 'auther'
        id = db.Column(db.Integer,primary_key=True)   #主键
        name = db.Column(db.String(64),unique=True)
        db.relationship('Book',backref = 'auther')      #用于查询一对多
    
    class Book(db.Model):
        __tablename__ = 'book'
        id = db.Column(db.Integer,primary_key=True)   #主键
        name = db.Column(db.String(64))
    
        au_book = db.Column(db.Integer,db.ForeignKey('auther.id'))
    
    db.drop_all()
    db.create_all()
    auther1 = Auther(name='金庸')
    auther2 = Auther(name='古龙')
    db.session.add_all([auther1,auther2])
    db.session.commit()
    
    book1 = Book(name='天龙八部',au_book=auther1.id)
    book2 = Book(name='射雕英雄传',au_book=auther1.id)
    book3 = Book(name='小李飞刀',au_book=auther2.id)
    book4 = Book(name='楚留香传奇',au_book=auther2.id)
    db.session.add_all([book1,book2,book3,book4])
    db.session.commit()
    

    3.插入数据的表单类

    '''表单验证类'''
    #添加数据的表单验证类
    class BookForm(FlaskForm):
        author_name = StringField(label='作者:',validators=[DataRequired('作者不能为空')])
        book_name = StringField(label='书籍:',validators=[DataRequired('书籍不能为空')])
        submit = SubmitField(label='添加')
    

    4.编写作者,书籍的展示和添加

    思路导图:


    @app.route('/',methods=['GET','POST'])
    def index():
        # 查询所有的作者
        authors = Auther.query.all()
    
        #实例化表单
        form = BookForm()
    
        if form.validate_on_submit():
    
            #获取表单数据  也可以 author_name = form.author_name.data
            author_name = request.form.get('author_name')
            book_name = request.form.get('book_name')
    
            #通过用户填写的作者name查询该作者对象
            author = Auther.query.filter_by(name = author_name).all()     
    
            if author:       #如果该作者存在,就判断该作者有没有用户填写的书籍
                book = Book.query.filter(Book.name == book_name,Book.au_book == author[0].id).all()
    
                if book:       #如果该书籍存在,就不能添加
                    flash('该作者和书籍已存在')
                else:          #不存在,就添加到数据库
                    bookobj = Book(name=book_name, au_book=author[0].id)     #创建该对象的书籍
                    db.session.add(bookobj)              #插入数据库
                    db.session.commit()
            else:
                #创建作者
                newau = Auther(name=author_name)
                db.session.add(newau)  # 插入数据库
                db.session.commit()
                #添加书籍
                bookobj = Book(name=book_name, au_book=newau.id)  # 创建该作者的书籍
                db.session.add(bookobj)  # 插入数据库
                db.session.commit()
    
            #不管是否添加成功,都要重新进入index页面
            return redirect(url_for('index'))
    
        return render_template('library.html',authors=authors,form=form)
    

    分析:
    当以get方式进入该视图函数时,要进行数据的展示页面,获取作者信息,以及表单的展示。然后返回library.html页面。
    当用户填写完数据后,以post方式提交表单,如果表单验证通过:

    1. 首先获取表单中的两个数据---作者name和书籍name。
    2. 判断如果作者存在,在数据库中查找是否有该作者写的该书籍,如果该书籍对象存在,那么就不能在添加了,如果该书籍不存在,那么就创建该书籍对象并添加到数据库中。
      3.如果该作者不存在,直接创建作者,提交数据库,创建该作者的书籍,提交数据库。
      4.不管添加是否成功,都重定向到index页面。
      library.html:
    <body>
    <h1>欢迎来到图书管理</h1>
    <h3>添加书籍</h3>
    <form action="" method="post">
        {{ form.csrf_token() }}
        {{ form.author_name.label }}
        {{ form.author_name }}
        <br>
        {{ form.book_name.label }}
        {{ form.book_name }}
        <br>
        {{ form.submit }}
        <br>
        {% for message in get_flashed_messages() %}
            {{ message }}
        {% endfor %}
        <br>
    </form>
    <ul>
        {% for author in authors %}
            <li>作者:{{ author.name }} <a href="{{ url_for('delete_author',author_id = author.id) }}">删除</a></li>
            <ul>
                {% for book in author.book %}
                    <li>书籍:{{ book.name }} <a href="{{ url_for('delete_book',book_id = book.id) }}">删除</a></li>
                {% endfor %}
    
            </ul>
        {% endfor %}
    
    </ul>
    </body>
    

    5.删除作者,删除书籍

    #删除作者
    @app.route('/delete_author/<int:author_id>')
    def delete_author(author_id):
    
        #获取要删除的作者对象
        author = Auther.query.get(author_id)
    
        for book in author.book:
            db.session.delete(book)
        db.session.delete(author)
    
        db.session.commit()
    
        return redirect(url_for('index'))
    
    #删除书籍
    @app.route('/delete_book/<int:book_id>')
    def delete_book(book_id):
    
        book = Book.query.get(book_id)     #获取该书籍
    
        db.session.delete(book)
        db.session.commit()
    
        return redirect(url_for('index'))
    

    分析:
    1.删除作者,不仅要删除该作者,还要删除该作者的所有书籍,那只要查找出来,删除即可。
    首先根据前台传过来的作者id -- author_id 获取该作者对象,根据表之间的关联查询该作者有那几本书,循环遍历出来,并一一删除,最后在删除该作者。提交数据库即可。
    重定向到index页面展示删除后的数据。
    2.删除书籍,通过前台传过来的book_id查询该书籍对象,删除它,提交数据库即可。
    重定向到index页面展示删除后的数据。

    相关文章

      网友评论

          本文标题:2020-06-13--flask07--flask基础07

          本文链接:https://www.haomeiwen.com/subject/hauatktx.html