美文网首页
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