前言
- 引出重寫的原因,我們是通過軟刪除的方式來刪除數據的(即通過status標識來確定數據是否作廢)
- 那么這樣的話,我們每一次查詢的時候都要寫上條件status=1很繁瑣。我們可以重寫filter_by方法
源碼介紹
如上圖所示我們現在使用的查詢方式並不是SQLAlchemy原生的查詢方式,而是flask_sqlalchemy(是對原生SQLAlchemy的一個封裝),是因為flask覺得原生的SQLAlchemy不是很方便,就以原生的為基礎自己封裝了一個flask_sqlalchemy實現了它自己的一些更加方便的查詢。所以說上面的query對象是flask_sqlalchemy下面的一個對象。
- 下面我們flask_sqlalchemy查看源碼
- 在__init__文件的407行有一個BaseQuery
- 可以看出是繼承了orm.Query,這個就是原生SQLAlchemy包里面的一個對象。我們可以看到在BaseQuery下面是沒有實現filter_by方法的。下面我們在看一下orm.Query的源碼
- 而在這個文件的1559行就找到了filter_by
- 可以看到他接收一組參數**kwargs,這個參數就是我們下圖傳入進來的鍵值對。kwargs是一個字典!!!
- 然后在filter_by內部進行了下圖源碼的處理(我們這里不用管)
- 如果說我們只需要自己實現filter_by,然后在filter_by的內部加上status=1,最后在調用基類的filter_by方法,就可以完成我們的覆蓋改寫。
代碼編寫
- 下面開始敲代碼啦:
- 首先導入flask_sqlalchemy的BaseQuery
-
上圖只是僅僅實現我們自己的邏輯了。我們還需要完成filter_by原有的邏輯。
-
調用基類下面的filter_by方法:上圖只是僅僅實現我們自己的邏輯了。我們還需要完成filter_by原有的邏輯。
-
在傳入字典的時候我們必須要對字典進行解包所以要傳入兩個*號
-
可以看到基類里面是有return的,所以我們要是不return就會有問題,我們需要return一下
- 現在我們就完成了自定義的Query,但是還沒有替換原來的BaseQuery,就要去看一下源碼。flask_sqlalchemy給了我們一個替換他原有BaseQuery的機會。這個機會就在flask_sqlalchemy這個他實例化的地方。下面我們在看一次源碼:
- 可以看到在她的構造函數里面是允許傳入一個自己的BaseQuery的
-
這樣我們就用自己定義的Query替代了flask_sqlalchemy的BaseQuery
-
上圖就完成了重寫flask_sqlalchemy的filter_by方法
-
所以當我們再調用query對象下面的filter_by方法的時候,就不是調用原來BaseQuery下面的filter_by了,而是調用我們自己改寫的這個filter_by。
-
在替換完成之后我們所有的filter_by中都不需要傳入status=1了。
附上代碼
class Query(BaseQuery):
def filter_by(self, **kwargs):
if 'status' not in kwargs.keys():
kwargs['status'] = 1
return super(Query, self).filter_by(**kwargs)
# 以下方法是重寫了BaseQuery類下面的方法,目的是拋出我們自定義的異常
def get_or_404(self, ident, description=None):
"""返回指定主鍵對應的行,如不存在,拋出自定義異常類"""
rv = self.get(ident)
if rv is None:
raise ValError(msg='未查詢到該數據')
return rv
def first_or_404(self, description=None):
"""返回查詢的第一個結果,如果未查到,拋出自定義異常類"""
rv = self.first()
if rv is None:
raise ValError(msg='未查詢到該數據')
return rv
db = SQLAlchemy(query_class=Query)