1. 程式人生 > >Flask高階應用06---模型的CRUD和高階用法

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:

  1. 查詢

    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 %}