作者: w2n1ck
資料集使得資料庫中的資料讀取和寫入資料就像閱讀和編寫JSON檔案一樣簡單。
dataset對於操作JSON、CSV檔案、NoSQL非常好用。
import dataset
連線MySQL資料庫:
db = dataset。connect(‘mysql://username:password@10。10。10。10/ctf?charset=utf8’)使用者名稱:username,密碼:password,資料庫地址(地址+埠):10。10。10。10,database名: ctf連線SQLite資料庫:db = dataset。connect(‘sqlite:///ctf。db’)連線PostgreSQL資料庫:db = dataset。connect(‘postgresql://scott:tiger@localhost:5432/mydatabase’)
一定要注意指定字元編碼
table = db[‘city’] #(選擇city表)user = table(‘name’) # 找出表中‘name’列屬性所有資料res = db。query(‘select name from table limit 10’) # 如果不需要檢視全部資料的話最好用limit,因為全部資料的載入非常非常耗時間for x in res:print x[‘name’] # 選name欄位的資料table。insert(dict(name=‘John Doe’, age=37))table。insert(dict(name=‘Jane Doe’, age=34, gender=‘female’))john = table。find_one(name=‘John Doe’)
在資料庫中查詢是否有同時滿足多個條件的資料:table。find_one(屬性1=屬性值1, 屬性2=屬性值2, …)
注:find_one速度很慢
插入資料
dataset會根據輸入自動建立表和欄位名
table = db[‘user’]# 或者table = db。get_table(‘user’)table。insert(dict(name=‘John Doe’, age=46, country=‘China’))table。insert(dict(name=‘Jane Doe’, age=37, country=‘France’, gender=‘female’))# 主鍵id自動生成
更新資料
table。update(dict(name=‘John Doe’, age=47), [‘name’])# 第二個引數相當於sql update語句中的where,用來過濾出需要更新的記錄
事務操作
事務操作可以簡單的使用上下文管理器來實現,出現異常,將會回滾
with dataset。connect() as tx:tx[‘user’]。insert(dict(name=‘John Doe’, age=46, country=‘China’))# 相當於:db = dataset。connect()db。begin()try:db[‘user’]。insert(dict(name=‘John Doe’, age=46, country=‘China’))db。commit()except:db。rollback()# 也可以巢狀使用:db = dataset。connect()with db as tx1:tx1[‘user’]。insert(dict(name=‘John Doe’, age=46, country=‘China’))with db as tx2:tx2[‘user’]。insert(dict(name=‘Jane Doe’, age=37, country=‘France’, gender=‘female’))
從表獲取資料
users = db[‘user’]。all()for user in db[‘user’]:# print(user[‘age’])# chinese_users = user。find(country=‘China’)john = user。find_one(name=‘John Doe’)
獲取非重複資料
db[‘user’]。distinct(‘country’)
刪除記錄
table。delete(place=‘Berlin’)
執行SQL語句
result = db。query(‘SELECT country, COUNT(*) c FROM user GROUP BY country’)for row in result:print(row[‘country’], row[‘c’])
匯出資料
result = db[‘users’]。all()dataset。freeze(result, format=‘json’, filename=‘users。json’)
JSON
JSON(JavaScript Object Notation) 是一種輕量級的資料交換格式,非常易於人閱讀和編寫。
import jsonjson。dumps 將 Python 物件編碼成 JSON 字串json。loads 將已編碼的 JSON 字串解碼為 Python 物件
MySQL資料庫
:
分類表-categories,包括類別web,reversing,crypto(加解密),mic等
題目表-tasks,包括題目id,題目名,flag,分值,檔案&地址,題目等級,題目詳細描述
flag表-flag,包括題目id,使用者id,得分,時間戳
使用者表-users,包括使用者id,使用者名稱,密碼
題目分類表-cat_task,包括題目id,題目類別id
flag表中每條資料由於是有題目ID task_id和使用者ID user_id來共同確認的,所以採用複合主鍵:primary key (task_id,user_id)
聯合主鍵和複合主鍵的區別
python裝飾器
Decorator透過返回包裝物件實現間接呼叫,以此插入額外邏輯
https://www。zhihu。com/question/26930016
wraps本身也是一個裝飾器,它能把原函式的元資訊複製到裝飾器函式中,這使得裝飾器函式也有和原函式一樣的元資訊了
from functools import wrapsdef logged(func):@wraps(func)def with_logging(*args,**kwargs):print func。__name__ + “was called”return func(*args,**kwargs)return with_logging@loggeddef f(x):“”“does some math”“”return x + x * xprint f。__name__ # prints ‘f’print f。__doc__ # prints ‘does some math’
web框架採用flask
from flask import Flask
引入Flask類,Flask類實現了一個WSGI(Web Server Gateway Interface)應用
app = Flask(__name__)
app是Flask的例項,它接收包或者模組的名字作為引數,但一般都是傳遞__name__
@app。route(‘/’)def hello_world():return ‘Hello World!’
使用app。route裝飾器會將URL和執行的檢視函式的關係儲存到app。url_map屬性上。處理URL和檢視函式的關係的程式就是路由,這裡的檢視函式就是hello_world
if __name__ == ‘__main__’:app。run(host=‘0。0。0。0’,port=9000)
使用這個判斷可以保證當其他檔案引用這個檔案的時候(例如from hello import app)不會執行這個判斷內的程式碼,也就是不會執行app。run函式。
執行app。run就可以啟動服務了。預設Flask只監聽虛擬機器的本地127。0。0。1這個地址,埠為5000。而我們對虛擬機器做的埠轉發埠是9000,所以需要制定host和port引數,0。0。0。0表示監聽所有地址,這樣就可以在本機訪問了。
伺服器啟動後,會呼叫werkzeug。serving。run_simple進入輪詢,預設使用單程序單執行緒的werkzeug。serving。BaseWSGIServer處理請求,實際上還是使用標準庫BaseHTTPServer。HTTPServer,透過select。select做0。5秒的while TRUE的事件輪詢。當我們訪問http://127。0。0。1:9000/,透過app。url_map找到註冊的/這個URL模式,就找到了對應的hello_world函式執行,返回hello world!,狀態碼為200。如果訪問一個不存在的路徑,如訪問http://127。0。0。1:9000/a,Flask找不到對應的模式,就會向瀏覽器返回Not Found,狀態碼為404
flask中jsonify的作用
jsonify的作用實際上就是將我們傳入的json形式資料序列化成為json字串,作為響應的body,並且設定響應的Content-Type為application/json,構造出響應返回至客戶端
效果等於json。dumps
jsonify的Content-Type欄位值為application/json
json。dumps的Content-Type欄位值為text/html
修改flask中靜態資料夾
修改的flask預設的static資料夾只需要在建立Flask例項的時候,把static_folder和static_url_path引數設定為空字串即可。
app = Flask(__name__, static_folder=”, static_url_path=”)
訪問的時候用url_for函式,res資料夾和static資料夾同一級:
url_for(‘static’, filename=’res/favicon。ico’)
werkzeug
werkzeug是一個WSGI工具包,可以作為一個Web框架的底層庫。它封裝好了很多Web框架的東西,例如 Request,Response等等。Flask框架就是一Werkzeug 為基礎開發的
generate_password_hash(password)
將使用者輸入的明文密碼加密成密文進行儲存
密碼加鹽雜湊函式。用來將明文密碼加密,返回加密後的密文,用來進行使用者註冊
函式定義:
werkzeug。security。generate_password_hash(password, method=‘pbkdf2:sha1’, salt_length=8)密文格式:method$salt$hashpassword: 明文密碼method: 雜湊的方式(需要是hashlib庫支援的),格式為pbpdf2:
check_password_hash(hash,password)
驗證經過generate_password_hash雜湊的密碼,將明文和密文進行比較,檢視是否一致,用來驗證使用者登入
函式定義:
werkzeug。security。check_password_hash(pwhash, password)pwhash: generate_password_hash生成的雜湊字串password: 需要驗證的明文密碼
flask中的session
rom flask import sessionuser = db[‘users’]。find_one(username=username)session[‘user_id’] = user[‘id’]
由於使用了session,所以需要設定一個secret_key用來做一些模組的hash
Flask Web Development 中的內容:
SECRET_KEY配置變數是通用金鑰,可在Flask和多個第三方擴充套件中使用。如其名所示,加密的強度取決於變數值的機密度。不同的程式要使用不同的金鑰,而且要保證其他人不知道你所用的字串。
SECRET_KEY的作用主要是提供一個值做各種HASH, 是在其加密過程中作為演算法的一個引數(salt或其他)。所以這個值的複雜度也就影響到了資料傳輸和儲存時的複雜度。
flask 變數規則
要給URL新增變數部分,你可以把這些特殊的欄位標記為
@route(‘/hello/
資料庫查詢
對dataset的資料查詢,使用冒號來為變數傳參。
select f。task_id from flags f where f。user_id = :user_id”’,user_id=session[‘user_id’])
模板渲染
使用render_template方法來渲染模板。將模板名和你想作為關鍵字的引數傳入模板的變數
MySQL
IFNULL(expr1,expr2)
如果expr1不是NULL,IFNULL()返回expr1,否則它返回expr2。
IFNULL()返回一個數字或字串值,取決於它被使用的上下文環境。
max函式是用來找出記錄集中最大值的記錄
對於left join,不管on後面跟什麼條件,左表的資料全部查出來,因此要想過濾需把條件放到where後面
對於inner join,滿足on後面的條件表的資料才能查出,可以起到過濾作用。也可以把條件放到where後面
在使用left jion時,on和where條件的區別如下:
on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。
where條件是在臨時表生成好後,再對臨時表進行過濾的條件。這時已經沒有left join的含義(必須返回左邊表的記錄)了,條件不為真的就全部過濾掉。
order by的用法
使用order by,一般是用來,依照查詢結果的某一列(或多列)屬性,進行排序(升序:ASC;降序:DESC;預設為升序)。當排序列含空值時:ASC:排序列為空值的元組最後顯示。DESC:排序列為空值的元組最先顯示。可以把null值看做無窮大select * from s order by sno desc, sage asc
group by的用法
group by按照查詢結果集中的某一列(或多列),進行分組,值相等的為一組1、細化集函式(count,sum,avg,max,min)的作用物件:未對查詢結果分組,集函式將作用於整個查詢結果。對查詢結果分組後,集函式將分別作用於每個組。SELECT cno,count(sno) from sc group by cno2、GROUP BY子句的作用物件是查詢的中間結果表分組方法:按指定的一列或多列值分組,值相等的為一組。使用GROUP BY子句後,SELECT子句的列名列表中只能出現分組屬性(比如:sno)和集函式(比如:count())select sno,count(cno) from sc group by sno3、多個列屬性進行分組select cno,grade,count(cno) from sc group by cno,grade4、使用HAVING短語篩選最終輸出結果只有滿足HAVING短語指定條件的組才輸出。HAVING短語與WHERE子句的區別:作用物件不同。1、WHERE子句作用於基表或檢視,從中選擇滿足條件的元組。2、HAVING短語作用於組,從中選擇滿足條件的組select sno from sc group by sno having count(cno)>3select sno,count(cno) from sc where grade>60 group by sno having count(cno)>3
MySQL的左連線、右連線、等值連線
1.左連線(left join )
select m。columnname……,n。* columnname…。。from left_table m left join right_table n on m。columnname_join=n。columnname_join and n。columnname=xxxwhere m。columnname=xxx…。。
ON是連線條件,用於把2表中等值的記錄連線在一起,但是不影響記錄集的數量。若是表left_table中的某記錄,無法在表right_table找到對應的記錄,則此記錄依然顯示在記錄集中,只是表right_table需要在查詢顯示的列的值用NULL替代;
ON連線條件中表n。columnname=xxx用於控制right_table表是否有符合要求的列值還是用NULL替換的方式顯示在查詢列中,不影響記錄集的數量;
WHERE字句控制記錄是否符合查詢要求,不符合則過濾掉
2.右連線(right join)
select m。columnname……,n。* columnname…。。from left_table m right join right_table n on m。 columnname_join=n。 columnname_join and m。 columnname=xxxwhere n。columnname=xxx…。。
3.等值連線
select m。columnname……,n。* columnname…。。from left_table m [inner] join right_table n on m。 columnname_join=n。 columnname_joinwhere m。columnname=xxx…。。 and n。columnname=xxx…。或者select m。columnname……,n。* columnname…。。from left_table m , right_table nwhere m。 columnname_join=n。 columnname_join andm。columnname=xxx…。。 and n。columnname=xxx…。
ON是連線條件,不再與左連線或右連線的功效一樣,除了作為2表記錄匹配的條件外,還會起到過濾記錄的作用,若left_table中記錄無法在right_table中找到對應的記錄,則會被過濾掉;
WHERE字句,不管是涉及表left_table、表right_table上的限制條件,還是涉及2表連線的條件,都會對記錄集起到過濾作用,把不符合要求的記錄刷選掉;
jinja2獲取迴圈索引
jinja2獲取迴圈{% for i in n %}的索引使用loop。index{% for i in names %}
flask 重定向和錯誤
可以用redirect()函式把使用者重定向到其它地方。放棄請求並返回錯誤程式碼,用abort()函式。
from flask import abort, redirect, url_for@app。route(‘/’)def index():return redirect(url_for(‘login’))@app。route(‘/login’)def login():abort(401)this_is_never_executed()
預設情況下,錯誤程式碼會顯示一個黑白的錯誤頁面。如果你要定製錯誤頁面,可以使用errorhandler()
裝飾器:
from flask import render_template@app。errorhandler(404)def page_not_found(error):return render_template(‘page_not_found。html’), 404
注意 render_template()呼叫之後的 404 。這告訴Flask,該頁的錯誤程式碼是404 ,即沒有找到。預設為200,也就是一切正常。
flask CSRF防護機制
@app。before_requestdef csrf_protect():if request。method == “POST”:token = session。pop(‘_csrf_token’, None)if not token or token != request。form。get(‘_csrf_token’):abort(403)def some_random_string():return hashlib。sha256(os。urandom(16)。hexdigest())def generate_csrf_token():if ‘_csrf_token’ not in session:session[‘_csrf_token’] = some_random_string()return session[‘_csrf_token’]
在flask的全域性變數裡面註冊 上面那個生成隨機token的函式
app。jinja_env。globals[‘csrf_token’] = generate_csrf_token
在網頁的模板是這麼引入的