美文网首页
day59-flask模型关联及图片上传

day59-flask模型关联及图片上传

作者: barriers | 来源:发表于2019-01-24 20:29 被阅读0次

    1与或非组合查询

    flask中查询可以组合查询
    filter(模型名.字段=值)可以接多个filter表示且操作;也可以直接在一个filter里面用逗号分开表示且操作
    and_ 且,可不写,默认情况就是且操作;not_ 或;or_ 或

    @blue.route('/sel_stu/', methods=['GET'])
    def sel_stu():
        stus = Student.query.filter(Student.s_name.contains('张')).filter
            (Student.s_age > 25).all()
        stus = Student.query.filter(Student.s_name.contains('张'),
            Student.s_age > 25).all()
        stus = Student.query.filter(and_(Student.s_name.contains('张'),
             Student.s_age > 25)).all()
        return '查询成功'
    
    @blue.route('/sel_stu/', methods=['GET'])
    def sel_stu():
        stus = Student.query.filter(or_(Student.s_name.contains('张'), 
            Student.s_age > 25)).all()
        return '查询成功'
    
    @blue.route('/sel_stu/', methods=['GET'])
    def sel_stu():
        stus = Student.query.filter(not_(Student.s_name.contains('张')), 
          Student.s_age > 25).all()
        return '查询成功'
    

    2分页

    flask中分页可以用paginate实现(内部借助offset和limit实现)
    对象.has_next/has_prev 是否有下一页/上一页
    对象.next_num/prev_num 下一页/上一页页码
    对象.page:当前页
    对象.pages:共多少页
    对象.iter_pages() 被循环取的迭代部分
    items分页对象中保存的页面数据

    @blue.route('/all_stu/', methods=['GET'])
    def all_stu():
        if request.method == 'GET':
             从url中获取page参数
            page = int(request.args.get('page', 1))
            pg = Student.query.paginate(page, 3)
             获取当页数据
            stus = pg.items
            return render_template('stus.html', stus=stus, pg=pg)
    

    如果循环中页码很多需要隐藏中间的部分页码时,在页面解析时

    {% for i in pg.iter_pages() %}
      {% if i %}
        <a href="{{ url_for('app.all_stu') }}?page={{ i }}">{{ i }}</a>
      {% else %}
        ...
      {% endif %}
    {% endfor %}
    

    页面解析及分页:

    <p>
      当前{{ pg.page }}页,共{{ pg.pages }}页
      {% if pg.has_prev %}
        <a href="{{ url_for('app.all_stu') }}?page={{ pg.prev_num }}">上一页</a>
        {% endif %}
        {% for i in pg.iter_pages() %}
          {% if i %}
            <a href="{{ url_for('app.all_stu') }}?page={{ i }}">{{ i }}</a>
          {% else %}
                ...
          {% endif %}
       {% endfor %}
    
      {% if pg.has_next %}
        <a href="{{ url_for('app.all_stu') }}?page={{ pg.next_num }}">下一页</a>
      {% endif %}
    </p>
    

    3一对多模型

    https://blog.zengrong.net/post/join-in-flash-sqlalchemy/

    3.1模型定义

    class Student(db.Model):
        __tablename__ = 'studnet'
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        s_name = db.Column(db.String(5), unique=True, nullable=False)
        s_age = db.Column(db.Integer, default=20)
        s_gender = db.Column(db.Boolean, default=1)
        creat_time = db.Column(db.DateTime, default=datetime.now)
        icon = db.Column(db.String(100), nullable=True)
        g_id = db.Column(db.Integer, db.ForeignKey('grade.id'), nullable=True)
    

    在字段中需要添加g_id = db.Column(db.Integer, db.ForeignKey('grade.id'), nullable=True),用于表示关联至哪个模型

    class Grade(db.Model):
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        g_name = db.Column(db.String(10), nullable=False, unique=True)
         定义了一个关联关系字段,和反向引用backref参数
        s_g = db.relationship('Student', backref='g')
    

    在最后需要添加s_g = db.relationship('Student', backref='g');定义了一个关联关系字段,和反向引用backref参数。用于查询。当通过本表查从表时,直接班级对象.s_g字段就能获取一个含有这个班级的所有学生列表。当通过从表查本表时,用从表对象.g就能获取班级对象。
    在一对多模型中:
    定义外键字段,db.ForeignKey('关联表名.id')
    关联字段=db.relationship('关联的模型名',backref='反向引用参数')(可以通过该字段查询对象)
    重点:relationship定义的字段,可以放在任何一个模型中

    3.2给关联字段赋值

    @blue.route('/create_stu_grade/', methods=['GET'])
    def create_stu_grade():
        if request.method == 'GET':
            获取id为1和2的两个学生
            stu1 = Student.query.get(1)
            stu2 = Student.query.get(2)
             分配给python班级
            g = Grade.query.filter(Grade.g_name == 'Python').first()
            stu1.g_id = g.id
            stu1.save()
    
            stu2.g_id = g.id
            stu2.save()
        return '分配学生对象成功'
    

    3.3通过班级查询学生

    @blue.route('/sel_stu_by_grade/', methods=['GET'])
    def sel_stu_by_grade():
        if request.method == 'GET':
            grade = Grade.query.filter_by(g_name='Python').first()
             通过班级对象查询该班级下的学生信息
            stus = grade.s_g
            stus_name = [stu.s_name for stu in stus]
            return '该班级下学生的姓名为:%s' % stus_name
    

    当通过关联字段所在的主表去查询另外的从表时,
    从表对象列表=主表对象.关联字段

    3.4通过学生查班级

    @blue.route('/sel_grade_by_stu/', methods=['GET'])
    def sel_grade_by_stu():
        if request.method == 'GET':
            stu = Student.query.filter(Student.s_name=='张三丰').first()
             通过学生查询班级的信息
            grd = stu.g
            return '班级为:%s' % grd.g_name
    

    当通过从表(没有关系字段的表)查主表时。主表对象=从表对象.关系字段别名

    3.5join联表多级筛选查询

    在一对多模型中,如果使用多方去查询一方,如果筛选条件只是在多这一方,那么使用普通查询就可以查询出合乎条件的结果,如果筛选条件既存在于多方中又存在于一方中,那么就需要使用join来进行联表并进行筛选。如下,发布时间存在于空气质量表中,而is_owned存在于网格表中,用普通查询则会显示空气质量表没有is_owned属性,所以需要使用join进行联表

    published_at_start = args.pop('published_at_start')
    published_at_end = args.pop('published_at_end')
    filter['is_owned'] = True
    grid_air_quality = GridAIrQualityModel.query.join(GridModel, 
            GridAIrQualityModel.grid_id==GridModel.id).
            filter(GridAIrQualityModel.published_at.between(published_at_start,
           published_at_end)).filter_by(**filter).order_by(GridAIrQualityModel.
           published_at).paginate(page=page_num, per_page=per_page)
    

    4多对多模型

    class Student(db.Model):
        __tablename__ = 'studnet'
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        s_name = db.Column(db.String(5), unique=True, nullable=False)
        s_age = db.Column(db.Integer, default=20)
        s_gender = db.Column(db.Boolean, default=1)
        creat_time = db.Column(db.DateTime, default=datetime.now)
    
    s_c = db.Table('s_c', db.Column('s_id', db.Integer, db.ForeignKey
       ('studnet.id')),db.Column('c_id', db.Integer, db.ForeignKey('course.id')))
    
    class Course(db.Model):
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        c_name = db.Column(db.String(10), unique=True, nullable=True)
        stu = db.relationship('Student', secondary=s_c, backref='cou')
    

    其中s_c为定义的中间表。多对多模型中定义外键字段是通过中间表,db.Table(表名,字段)完成的;
    关联字段=db.relationship('关联的模型名',secondary=中间表,backref='反向引用参数');
    重点:relationship定义的字段,可以放在任何一个模型中。

    4.1添加课程

    @blue.route('/add_cou/', methods=['GET'])
    def add_cou():
        if request.method == 'GET':
            cou = ['高等数学','线性代数','几何概论','概率论','地史学','语文']
            for name in cou:
                cour = Course()
                cour.c_name = name
                db.session.add(cour)
            db.session.commit()
        return '添加课程成功'
    

    4.2给学生添加课程

    @blue.route('/stu_cou/', methods=['GET'])
    def stu_cou():
        if request.method == 'GET':
             给扫地僧加两门课程
            stu = Student.query.filter(Student.s_name=='扫地僧').first()
            cou1 = Course.query.filter(Course.c_name=='地史学').first()
            cou2 = Course.query.filter(Course.c_name=='语文').first()
            stu.cou.append(cou1)
            stu.cou.append(cou2)
            db.session.commit()
            return '添加成功'
    

    给学生添加课程方法:学生对象.关联字段别名.append(课程对象)

    4.3给课程添加学生

    @blue.route('/stu_cou/', methods=['GET'])
    def stu_cou():
        if request.method == 'GET':
             给地史学添加一个学生
            stu1 = Student.query.filter(Student.s_name=='张三丰').first()
            cou1 = Course.query.filter(Course.c_name=='地史学').first()
            cou1.stu.append(stu1)
            db.session.commit()
            return '添加成功'
    

    给课程添加学生方法:课程对象.关联字段.append(学生对象)

    4.4给学生删除一门课程

    @blue.route('/stu_cou/', methods=['GET'])
    def stu_cou():
        if request.method == 'GET':
             给扫地僧删除地史学
            stu = Student.query.filter(Student.s_name=='扫地僧').first()
            cou1 = Course.query.filter(Course.c_name=='地史学').first()
            stu.cou.remove(cou1)
            db.session.commit()
            return '添加成功'
    

    删除方法:学生对象.关联字段别名.remove(课程对象)

    5接收图片

    @blue.route('/edit_stu/<int:id>/', methods=['GET', 'POST'])
    def edit_stu(id):
        if request.method == 'GET':
            stu = Student.query.get(id)
            return render_template('rdit.html', stu=stu)
    
        if request.method == 'POST':
             接收图片,并保存图片
            icon = request.files.get('image')
             获取项目的跟路径
            BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
             获取媒体文件的路径
            STATIC_DIR = os.path.join(BASE_DIR, 'static')
            MEDIA_DIR = os.path.join(STATIC_DIR, 'media')
             随机生成图片的名称
            filename = str(uuid.uuid4())
             获取文件格式(后缀)
            a = icon.mimetype.split('/')[-1:][0]
             生成文件名及其格式
            name = filename + '.' + a
             拼接图片地址
            path = os.path.join(MEDIA_DIR, name)
             保存
            icon.save(path)
             修改用户的icon字段
            stu = Student.query.get(id)
             将文件名赋值给icon字段
            stu.icon = name    
            stu.save()
             重定向到列表页面
            return redirect(url_for('app.all_stu'))
    

    icon = request.files.get('image'):获取上传文件中的图片;
    os.path.abspath(file):获取当前文件的绝对路径。os.path.dirname(路径):获取路径的上层的路径。BASE_DIR代表获取项目的文件路径。
    STATIC_DIR = os.path.join(BASE_DIR, 'static'):获取BASE_DIR文件(项目文件)下的static文件路径。
    MEDIA_DIR = os.path.join(STATIC_DIR, 'media')获取STATIC_DIR文件夹下的media的路径。
    a = icon.mimetype.split('/')[-1:][0]获取文件的mimetype属性并对其进行切割。也可写成a = icon.mimetype.split('/')[-1]都是获取文件的后缀。
    name = filename + '.' + a:组装要保存的文件的名字。
    path = os.path.join(MEDIA_DIR, name):获取图片的路径
    icon.save(path)保存图片,将图片保存在path路径。
    stu.icon = name将图片名字赋值给icon属性。

    6页面提交图片

    <form action="" method="post" enctype="multipart/form-data">
        <p>姓名:{{ stu.s_name }}</p>
        <p>头像:<input type="file" name="image"></p>
        <p><input type="submit" value="提交"></p>
    </form>
    

    7页面解析图片

    {% for stu in stus %}
        <tr>
        <td>{{ loop.index }}</td>
        <td>{{ stu.s_name }}</td>
        <td>{{ stu.s_age }}</td>
        <td><img src="/static/media/{{ stu.icon }}" style="width: 50px;height: 50px;"></td>
        <td><a href="{{ url_for('app.edit_stu', id=stu.id) }}">编辑</a></td>
      </tr>
    {% endfor %}
    

    <img src="/static/media/{{ stu.icon }}">页面解析图片路径
    <a href="{{ url_for('app.edit_stu', id=stu.id) }}">编辑</a>页面调用后端函数并传输参数

    相关文章

      网友评论

          本文标题:day59-flask模型关联及图片上传

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