Flask高階應用06---模型的CRUD和高階用法
一、資料對映(資料庫crud基礎操作)
注意:在遷移前首先要開啟資料庫mysql
1.建立模型==create_all()
對建立的模型資料進行遷移,這個方法只能用於首次建立,後面遷移需要用migrate(不建議用),建議用sql語句,orm實現的資料庫遷移不是最有方式
@blue.route('create_db/') #設定路由資訊
def create_db():
db.create_all() #呼叫flask方法
return '建立成功'
執行專案,瀏覽器中顯示建立成功後,檢視資料庫可以看到此時生成剛建立的學生表
mysql> show tables;
+------------------+
| Tables_in_flask5 |
+------------------+
| student |
2.刪除表(謹慎使用!!)==drop_all()
@blue.route('/drop_db/')
def drop_db():
# 刪除表
db.drop_all()
return '刪除成功'
3.給學生表新增資訊:
語法:
類名.query.xxx
獲取查詢集:
all() filter(類名.屬性名==xxx) filter_by(屬性名=xxx)
資料操作:
在事務中處理,資料插入
db.session.add(object)
db.session.add_all(list[object])
db.session.delete(object)
db.session.commit() #提交事務,使用commit提交我們的新增資料的操作
修改和刪除基於查詢
(1)新增一條學生資訊
@blue.route('/create_stu/') def create_stu(): #實現建立 stu = Student() stu.s_name = '小明' db.session.add(stu) db.session.commit() return '建立學生資訊成功'
提交事務,使用commit提交我們的新增資料的操作
**方式優化:**封裝一個save()方法
在模型module.py中定義一個方法
def save(self):
db.session.add(self)
db.session.commit()
在檢視中直接呼叫save方法:
@blue.route('/create_stu/')
def create_stu():
#實現建立方法二:模型中單獨定義一個方法
stu = Student()
stu.s_name = '小明1'
stu.save()
return '建立學生資訊成功'
(2)批量新增—建立多個學生資訊
定義列表,然後用for迴圈
@blue.route('/create_stu_all/')
def create_stu_all():
names = ['宋江','武松','李逵','林沖','魯智深']
for name in names:
stu = Student()
stu.s_name = name
#方式一:
stu.save() #呼叫封裝的save方法
return '批量建立成功'
優化:傳入列表,用add_all,(推薦)
@blue.route('/create_stu_all/')
def create_stu_all():
names = ['宋江','武松','李逵','林沖','魯智深']
stu_list = []
for name in names:
stu = Student()
stu.s_name = name
stu_list.append(stu) #append給列表新增內容
db.session.add_all(stu_list)
db.session.commit()
return '批量建立成功'
效果新增成功:
mysql> select * from student;
+----+--------+-------+
| id | s_name | s_age |
+----+--------+-------+
| 1 | 小明 | 19 |
| 2 | 宋江 | 19 |
| 3 | 武松 | 19 |
| 4 | 李逵 | 19 |
| 5 | 林沖 | 19 |
| 6 | 魯智深 | 19 |
+----+--------+-------+
6 rows in set (0.07 sec)
4.查詢資訊==過濾(filter、filter_by)
基本格式:(注意等於號不同!!)
filter(類名.屬性名==xxx)
filter_by(屬性名=xxx)
【例】
@blue.route('/sel_stu/')
def sel_stu():
#查詢,filter(),filter_by
#返回型別是querybase
stu = Student.query.filter(Student.s_name =='宋江')
stu = Student.query.filter_by(s_name='武松')
return '查詢成功'
注意; .all()後面不能再接filter了,因為獲取的是列表,django中可以後面接filter,因為獲取的是queryset,是可以通過下標拿值的
【例】將學生的全部資訊獲取到,並且返回給頁面,在頁面中使用for迴圈去解析即可
@blue.route("/getstudents/")
def get_students():
students = Student.query.all()
return render_template("StudentList.html", students=students)
【例】獲取s_id=1的學生的資訊
寫法1:
students = Student.query.filter(Student.id==1)
寫法2:
students = Student.query.filter_by(id=2)
注意:filter中可以接多個過濾條件
寫法3:(直接用sql語句)===excute
sql = 'select * from student where id=1'
students = db.session.execute(sql)
5.修改學生資訊
【例】修改學生的資訊update
寫法1:
students = Student.query.filter_by(id=3).first()
students.s_name = '哈哈'
db.session.commit()
寫法2:
Student.query.filter_by(s_id=3).update({'s_name':'娃哈哈'})
db.session.commit()
6.刪除學生資訊
【例1】用filter
@blue.route('/delete_stu/<int:id>/')
def delete_stu(id):
stu = Student.query.filter(Student.id ==id).first()
db.session.delete(stu)
db.session.commit()
return '刪除成功'
執行後在url中輸入
。。。。./delete_stu/2 執行成功可以看到資料庫表中第二條資料刪除
【例2】刪除一個學生的資訊用filter_by
寫法1:
stu = Student.query.filter_by(id=2).first()
db.session.delete(stu)
db.session.commit()
寫法2:
students = Student.query.filter_by(id=1).all()
db.session.delete(students[0])
db.session.commit()
注意:filter_by後的結果是一個list的結果集
重點注意:在增刪改中如果不commit的話,資料庫中的資料並不會更新,只會修改本地快取中的資料,所以一定需要db.session.commit()
【科普】GIL
二、 深入資料庫增刪改查
定義模型,並定義初始化的函式:
class Student(db.Model):
s_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
s_name = db.Column(db.String(16), unique=True)
s_age = db.Column(db.Integer, default=1)
__tablename__ = "student"
def __init__(self, name, age):
self.s_name = name
self.s_age = age
1、批量增加
第一種方式–add_all:
@blue.route('/createstus/')
def create_users():
stus = []
for i in range(5):
# 例項化Student的物件
s = Student()
# 物件的屬性賦值
s.s_name = '張三%s' % random.randrange(10000)
s.s_age = '%d' % random.randrange(100)
stus.append(s)
# 新增需要建立的資料
db.session.add_all(stus)
# 提交事務到資料庫
db.session.commit()
return '建立成功'
注:在建立單條資料的時候使用db.session.add(),在建立多條資料的時候使用db.session.add_all()
第二種方式:
@blue.route('/createstus/')
def create_users():
stus = []
for i in range(5):
# 使用類的初始化去建立Student物件
s = Student('張三%s' % random.randrange(10000),
'%d' % random.randrange(100))
stus.append(s)
db.session.add_all(stus)
db.session.commit()
return '建立成功'
2、 使用運算子查詢
獲取查詢集
filter(類名.屬性名.運算子(‘xxx’))
filter(類名.屬性 數學運算子 值)
運算子:
contains: 包含
startswith:以什麼開始
endswith:以什麼結束
in_:在範圍內
like:模糊
__gt__: 大於
__ge__:大於等於
__lt__:小於
__le__:小於等於
篩選:
offset()
limit()
order_by()
get()
first()
paginate()
邏輯運算:
與
and_
filter(and_(條件),條件…)
或
or_
filter(or_(條件),條件…)
非
not_
filter(not_(條件),條件…)
【例1】查詢學生的id為3,4,5,6,16的的學生資訊,使用in_邏輯運算
@blue.route('/getstubyids/')
def get_stu_by_ids():
students = Student.query.filter(Student.s_id.in_([3,4,5,6,16]))
return render_template('StudentList.html', students=students)
【例2】查詢學生的年齡小於18歲的學生的資訊
Student.query.filter(Student.s_age < 18)
【例3】查詢學生的年齡小於18歲的學生的資訊,__lt__小於
students = Student.query.filter(Student.s_age.__lt__(15))
【例4】查詢學生的年齡小於等於18歲的學生的資訊,__le__小於等於
students = Student.query.filter(Student.s_age.__le__(15))
【例5】查詢學生的姓名以什麼開始或者以什麼結尾的學生的資訊startswith和endswith
students = Student.query.filter(Student.s_name.startswith('張'))
students = Student.query.filter(Student.s_name.endswith('2'))
【例6】查詢id=4的學生的資訊
Student.query.get(4)
獲取的結果是學生的物件
3、模糊查詢
模糊搜尋like
%:代表一個或者多個
_:代表一個
Student.query.filter(Student.s_name.like('%張%'))
4、排序查詢
跳過offset幾個資訊,擷取limit結果的幾個值
# 按照id降序排列
stus = Student.query.order_by('-s_id')
# 按照id升序排列
stus = Student.query.order_by('s_id')
stus = Student.query.order_by(asc('s_id'))
stus = Student.query.order_by('s_id asc')
# 按照id降序獲取三個
stus = Student.query.order_by('-s_id').limit(3)
stus = Student.query.order_by('s_id desc').limit(3)
from sqlalchemy import desc
stus = Student.query.order_by(desc('s_id')).limit(3)
# 獲取年齡最大的一個
stus = Student.query.order_by('-s_age').first()
# 跳過3個數據,查詢5個資訊
stus = Student.query.order_by('-s_age').offset(3).limit(5)
# 跳過3個數據
stus = Student.query.order_by('-s_age').offset(3)
# 獲取id等於24的學生
stus = Student.query.filter(Student.s_id==24)
stus = Student.query.get(24)
例子3:
-
查詢
from sqlalchemy import and_, or_, not_
查詢多個條件
stus = Student.query.filter(Student.s_age18, Student.s_name’雅典娜’)
and_ 並且條件
stus = Student.query.filter(and_(Student.s_age18, Student.s_name’雅典娜’))
or_ 或者條件
stus = Student.query.filter(or_(Student.s_age18, Student.s_name’火神’))
not_ 非
stus = Student.query.filter(not_(Student.s_age18), Student.s_name’火神’)
查詢姓名不包含’可愛‘,並且年齡不等於12的學生
stus = Student.query.filter(not_(Student.s_name.contains(‘可愛’)), not_(Student.s_age == 12))
5、分頁查詢
(1)分頁的四種方式:
(1)offset+limit
(2)切片
(3)sql語句
(4)paginate()方法
(2)分頁的屬性
【例】在檢視中定義路由和方法(這裡將前三種方式註釋掉,採用paginate分頁)
#app/views
@blue.route('/paginate/')
def stu_paginate():
page = int(request.args.get('page', 1))
"""
# 1. offset+limit
stus = Student.query.offset((page-1) * 2).limit(2)
# 2. 切片
stus = Student.query.all()[(page-1)*2:page*2]
# 3. sql語句
sql = 'select * from student limit %s,%s' % ((page-1)*2, 2)
stus = db.session.execute(sql)
"""
# 4. paginate()方法
paginate = Student.query.paginate(page, 2)
stus = paginate.items
return render_template('stus.html', stus=stus, paginate=paginate)
在模板中展示內容
注意:url_for後面接(藍圖名.方法名)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table>
<thead>
<th>id</th>
<th>姓名</th>
<th>年齡</th>
</thead>
<tbody>
{% for stu in stus %}
<tr>
<td>{{ stu.id }}</td>
<td>{{ stu.s_name }}</td>
<td>{{ stu.s_age }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<br>
<p>當前{{ paginate.page }}頁,共有{{ paginate.pages }}頁</p>
{% if paginate.has_prev %}
<a href="{{ url_for('app.stu_paginate') }}?page={{ paginate.prev_num }}">上一頁</a>
{% endif %}
{% for i in paginate.iter_pages() %}
<a href="{{ url_for('app.stu_paginate') }}?page={{ i }}">{{ i }}</a>
{% endfor %}
{% if paginate.has_next %}
<a href="{{ url_for('app.stu_paginate') }}?page={{ paginate.next_num }}">下一頁</a>
{% endif %}
</body>
</html>
實現效果:
【例2】後端資料處理:
# 方法一:手動實現分頁,使用offset和limit
page = int(request.args.get('page', 1))
stus = Student.query.offset((page-1)*5).limit(5)
# 方法二: 使用切片[:]
s_page = (page - 1)*5
e_page = page * 5
stus = Student.query.all()[s_page: e_page]
# 方法三:使用paginate
# 查詢第幾頁的資料
page = int(request.args.get('page', 1))
# 每一頁的條數多少,預設為10條
per_page = int(request.args.get('per_page', 10))
# 查詢當前第幾個的多少條資料
paginate = Student.query.order_by('-s_id').paginate(page, per_page, error_out=False)
stus = paginate.items
前端資料展示:
<h2>學生資訊</h2>
{% for stu in stus %}
id:{{ stu.s_id }}
姓名:{{ stu.s_name }}
年齡:{{ stu.s_age }}
<br>
{% endfor %}
<br>
總頁數: {{ paginate.pages }}
<br>
一共{{ paginate.total }}條資料
<br>
當前頁數:{{ paginate.page }}
<br>
{% if paginate.has_prev %}
<a href="/stupage/?page={{ paginate.prev_num }}">上一頁</a>:{{ paginate.prev_num }}
{% endif %}
{% if paginate.has_next %}
<a href="/stupage/?page={{ paginate.next_num }}">下一頁</a>:{{ paginate.next_num }}
{% endif %}
<br>
<br>
頁碼:{% for i in paginate.iter_pages() %}
<a href="/stupage/?page={{ i }}">{{ i }}</a>
{% endfor %}