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>页面调用后端函数并传输参数
网友评论