用Python操作Redis資料庫
Redis官網整理一份Node.js, Python, PHP,…等各種語言的Redis前端程式庫,本文使用Python語言,並採用官網推薦的redis-py程式庫。
先執行pip命令安裝redis程式庫:
pip install redis
透過Python連線到Redis Labs線上資料庫的第一個步驟是建立redis物件:
Redis物件的操作指令(方法)名稱,就是小寫的Redis CLI命令名稱,只有少數例外。例如:
- set():設定字串鍵值
- get():取得字串鍵值
- delete():刪除鍵值。Redis CLI的刪除命令寫成DEL,但由於del是Python的保留關鍵字(Python內建的刪除變數指令),所以這裡改名成delete()。
- hmset():設定雜湊(hash)的多組欄位和值。
- hgetall():取得雜湊的全部欄位和值。
完整的指令列表,請參閱Redis程式庫官方說明文件。
實際用Python 3直譯器測試連線操作Redis Labs資料庫,請在命令提示字元或終端機中啟動Python,再輸入底下的指令:
接著透過Redis物件操作資料庫。底下的命令將設定一個其值為‘hello!’的‘foo’鍵。讀取出的值為byte(位元組)類型,所以字串資料被b”包圍:
若執行set()方法出現如下的錯誤訊息,請確認主機、埠號或密碼是否輸入正確。
透過Redis程式庫存取的字串都會經過UTF-8編碼成位元組格式:
所以取出資料之後,要透過decode()解碼:
讀寫雜湊型鍵值
底下是建立名叫“phones:2”的雜湊型資料,存入Python字典值的例子:
使用Redis資料庫儲存Heroku平台程式的全域資料
本單元將改寫《超圖解Python程式設計入門》第13章「紀錄心情留言悄悄話」的LINE聊天程式,把存在全域變數的悄悄話改存在Redis Labs資料庫,這樣的話,將此LINE程式佈署到Heroku平台也不會發生資料不同步的情況。
存在Redis的LINE用戶資料,將以 “users:用戶ID” 格式的鍵名儲存,如下圖所示:
本例將改寫書本的bot_secr.py範例檔,負責連線Redis Labs與存取資料的程式,全都歸納到RedisUser類別,這是類別的部份程式碼:
這段自訂類別程式可以擺在import敘述之後:
完整的RedisUser類別程式碼如下:
class RedisUser(): def __init__(self, host, port, password): self.rds = redis.Redis( host=host, port=port, password=password) def get_words(self, id): ''' 傳回UTF-8解碼後的悄悄話文字 ''' words = self.rds.hget(f'users:{id}', 'words').decode('utf-8') return words def set_words(self, id, val): ''' 設定用戶的悄悄話 ''' self.rds.hset(f'users:{id}', 'words', val) def set_save(self, id, val): self.rds.hset(f'users:{id}', 'save', val) def get_save(self, id): ''' 傳回轉成整數的寫入狀態值,0或1。 ''' save = self.rds.hget(f'users:{id}', 'save') return int(save) def get_name(self, id): ''' 傳回UTF-8解碼後的用戶名字 ''' name = self.rds.hget(f'users:{id}', 'name').decode('utf-8') return name def check(self, id, name): exist = self.rds.exists(f'users:{id}') if exist: print('用戶已經存在,id:', id) else: print('新增用戶,id:', id) self.rds.hmset(f'users:{id}', { 'name': name, 'words': '', 'save': 0 })
自訂類別物件時,要傳入Redis主機位址、埠號和密碼,例如,底下敘述將一個名叫redis_user的物件。
# 請自行替換主機、埠號和密碼 redis_user = RedisUser('redis-1984.redislabs.com', 1984, 'zzzzz')
原本使用全域變數存取悄悄話的程式,都要改成透過redis_user物件操作,像處理回應文字的reply_text函式:
def reply_text(token, id, txt): ''' 處理回應文字 ''' if (txt == 'Hi') or (txt == "你好"): name = redis_user.get_name(id) reply = f"{name}你好!" elif '悄悄話' in txt: words = redis_user.get_words(id) if words != '': reply = f'你的悄悄話是:\n\n{words}' else: reply = '放膽說出心裡的話吧~' redis_user.set_save(id, 1) # 準備儲存祕密 elif redis_user.get_save(id): redis_user.set_words(id, txt) # 儲存祕密 redis_user.set_save(id, 0) # 停止儲存祕密 reply = '我會好好保護這個祕密~' else: reply = txt msg = TextSendMessage(reply) line_bot_api.reply_message(token, msg)
以及接收文字訊息的事件處理程式:
@handler.add(MessageEvent, message=TextMessage) def handle_message(event): ''' 接收文字訊息的事件處理程式 ''' profile = line_bot_api.get_profile(event.source.user_id) # 紀錄用戶資料 _id = event.source.user_id _name = profile.display_name _txt = event.message.text redis_user.check(_id, _name) reply_text(event.reply_token, _id, _txt)
程式修改完畢,命名成bot_secr.py存檔。
佈署網站應用程式到Heroku平台
參閱10-23頁「Heroku雲端應用程式的檔案結構」單元的說明,在src路徑準備好這些檔案:
然後依照10-32頁「設置Heroku CLI與發布檔案」的說明,在src路徑執行git init(如果之前沒有在此路徑初始化git的話),再依序執行add, commit和push命令。
程式佈署完畢之後,記得到LINE開發人員頁面修改callback路徑,就能在LINE app上測試。
你好,
當我在line 輸入’悄悄話’後,程式出現
‘NoneType’ object has no attribute ‘decode’.
請問發生了甚麼error?
Thanks very much
應該是讀取使用者資料的程式碼沒有改到,這是完整的程式:
thanks,
jeffrey