Hello!大家好!都讓開!
是的沒錯,這次准備手敲一個非常牛批之《老閆真牛批-抽獎系統》
o(* ̄︶ ̄*)o
o(* ̄︶ ̄*)o
其實也么有很牛批哈,裝個x!!
o(* ̄︶ ̄*)o
o(* ̄︶ ̄*)o
自從上次寫了數字猜猜猜后,就對這種小游戲上癮了,既好玩,又能鞏固知識;
所以呢這次就再寫一個小游戲,但是打算寫個稍微復雜一點的
思前想后,覺得抽獎系統到時一個不錯的選擇
好了,圓規正傳,開始今天的裝x之旅!
首先,先來搭個架子,
好,架子搭好之后,正式開始動工!
首先先初始化一下我們的獎品庫json文件和用戶庫json文件,為什要用json文件呢,是因為這個方便哈,還有就是想練習下文件的讀寫
第二步,開始寫基礎操作函數模塊base.py
首先,我們先判斷一下gift.json和user.json的文件格式,路徑
這里可以把判斷的函數寫到公共函數模塊utils.py
1 # 判斷文件類型路徑 2 def check_file(path): 3 if not os.path.exists(path): # os.path.exists路徑存在則返回True,路徑損壞返回False 4 raise NotPathError('Not Found path') 5 6 if not path.endswith('.json'): # str.endswith('.json')判斷字符串結尾是不是以指定 7 raise FormatError('need json format') 8 9 if not os.path.isfile(path): # os.path.isfile判斷路徑是否為文件 10 raise NotFileError('this is not a file')
之后在base.py引用這個函數,來驗證兩個json文件
# coding:utf-8 import osimport json from common.utils import check_file class Base(object): def __init__(self, user_json, gift_json): self.user_json = user_json self.gift_json = gift_json self.__check_user_json() self.__check_gift_json() # 判斷user_json文件的類型以及地址 def __check_user_json(self): check_file(path=self.user_json) # 判斷gift_json文件的類型以及地址 def __check_gift_json(self): check_file(path=self.gift_json)
由於系統很多地方肯定是會有寫入文件的這個操作,所以干脆先寫一個寫入文件的函數,后面方便一些
# 定義一個寫入的函數 def __save(self, data, path): json_data = json.dumps(data) with open(path, 'w') as f: f.write(json_data)
下面就是寫入用戶函數,我初步的想法是,用戶信息包含用戶名,權限,是否啟用,創建時間,修改時間,抽到的獎品列表
是否啟用默認給了True,創建時間和修改時間自動寫入,獎品列表初始化為空的
那么只需要傳入用戶名和權限就可以了
注:下面的拋出異常代碼,是我自定義的,后面我會統一貼出來
# 寫入user信息 def __write_user(self, **user): # 判斷入參是否合規,是否包含username和role if "username" not in user: raise ValueError('missing username') if "role" not in user: raise ValueError('missing role') user['active'] = True user['create_time'] = time.time() user['update_time'] = time.time() user['gifts'] = [] users = self.__read_user() # 如果username已經存在了,那就拋出異常 if user['username'] in users: raise UserExistsError('username: %s had exists' % user['username']) # 如果username不存在,那就寫入文件 users.update( {user['username']: user} ) # 轉碼為json,並寫入 self.__save(data=users, path=self.user_json)
既然有寫出的操作,那就肯定會有讀的操作吧,那就再寫一個讀取user文件的方法
# 讀取user文件,並解碼為字典格式 def __read_user(self, time_to_str=False): with open(self.user_json, 'r') as f: data = json.loads(f.read()) # 把文件的時間戳改為字符串格式 if time_to_str is True: for k, v in data.items(): v['create_time'] = timestamp_to_string(v['create_time']) v['update_time'] = timestamp_to_string(v['update_time']) # 這里用的是時間戳轉碼,函數會在下面寫出 data[k] = v return data
由於寫入用戶信息的時候,創建時間和修改時間是以時間戳的格式寫進去的,讀出來的時候看着不方便,所以就在公共函數模塊,寫了一個時間戳轉碼的函數
utils.py
# 時間戳格式化 def timestamp_to_string(timestamp): time_obj = time.localtime(timestamp) time_str = time.strftime('%Y-%m-%d %H:%M:%S', time_obj) return time_str
讓我們再來想想,既然定義了有權限字段,那肯定會有修改權限的操作
那就搞一個修改權限role字段的方法吧
判斷role是否符合規范的里的 ROLES 是我在常量模塊consts.py里定義了一個列表,固定了兩種寫法
如果傳入的role字段跟列表里的對比不上,那就說明傳的不規范
# 修改role字段 def __change_role(self, username, role): users = self.__read_user() user = users.get(username) if not user: return False # 判斷入參role是否符合規范 if role not in ROLES: raise RoleError('not use role: %s' % role) user['role'] = role user['update_time'] = time.time() users[username] = user self.__save(data=users, path=self.user_json) return True
既然能修改權限了,狀態也得能讓人修改吧
# 修改active字段 def __change_active(self, username): users = self.__read_user() user = users.get(username) if not user: return False user['active'] = not user['active'] user['update_time'] = time.time() users[username] = user self.__save(data=users, path=self.user_json) return True
既然能寫入用戶,那也得能刪除用戶是不
搞起
# 刪除用戶 def __delete_user(self, username): users = self.__read_user() user = users.get(username) if not user: return False delete_user = users.pop(username) self.__save(data=users, path=self.user_json) return delete_user
好了,操作用戶這一塊算是基本搞定,下面開始搞獎品庫文件
先來頂一個初始化獎品庫結構的文件
def __init_gift(self): # 等級越高,獎品約稀有,每個等級里面又包含幾種等級的獎品 data = { 'level1': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level2': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level3': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level4': { 'level1': {}, 'level2': {}, 'level3': {} } } gifts = self.__red_gift() if len(gifts) != 0: return self.__save(data=data, path=self.gift_json)
老樣子,在搞一個讀取的方法
# 讀取獎品文件內容 def __red_gift(self): with open(self.gift_json, 'r') as f: data = json.loads(f.read()) return data
寫到后面,發現上面寫的那個讀取的方法,不夠完善,很多地方需要用到對應層級的數據,所以干脆寫一個方法
這個方法能獲取到對應層級的數據,方便很多
def __check_and_getgift(self, first_level, second_level, gift_name): if first_level not in FIRSTLEVELS: raise LevelError('first level not exists: %s' % first_level) if second_level not in SECONDLEVELS: raise LevelError('second level not exists: %s' % second_level) gifts = self.__red_gift() level_one = gifts[first_level] # 獲取level的對象"level1": {"level1": {}, "level2": {}}, "level3": {}} level_two = level_one[second_level] # 獲取level2的對象"level2": {} if gift_name not in level_two: return False return { 'level_one': level_one, 'level_two': level_two, 'gifts': gifts }
既然是獎品庫,那肯定得有添加獎品的步驟,所以就搞一個添加獎品的方法
這里比較復雜,也是搞了我好久時間
# 添加獎品到gift_json文件 def write_gift(self, first_level, second_level, gift_name, gift_count): if first_level not in FIRSTLEVELS: raise LevelError('first level not exists: %s' % first_level) if second_level not in SECONDLEVELS: raise LevelError('second level not exists: %s' % second_level) gifts = self.__red_gift() current_gift_pool = gifts[first_level] # 獲取level的對象"level1": {"level1": {}, "level2": {}}, "level3": {}} current_second_gift_pool = current_gift_pool[second_level] # 獲取level2的對象"level2": {} # 如果傳入的count小於等於0,那就默認count為1 if gift_count <= 0: gift_count = 1 # 如果添加的獎品已經存在獎品庫,那么就把添加的商品庫存+1 if gift_name in current_second_gift_pool: current_second_gift_pool[gift_name]['count'] = current_second_gift_pool[gift_name]['count'] + gift_count else: # 如果添加的商品不在獎品庫,那就把獎品寫入文件 current_second_gift_pool[gift_name] = { 'name': gift_name, 'count': gift_count } # 還原level2的文件內容 current_gift_pool[second_level] = current_second_gift_pool # 還原level1的文件內容 gifts[first_level] = current_gift_pool # 編碼為json以及寫入json文件 self.__save(data=gifts, path=self.gift_json)
接下來是修改獎品庫存的方法
如果傳入獎品數量 那就減去傳入的數量
如果不傳入,那獎品數量就默認減一
這塊可能后面要改,因為要驗證admin還是普通用戶
先這樣吧
def __update_gift(self, first_level, second_level, gift_name, gift_count): data = self.__check_and_getgift( first_level=first_level, second_level=second_level, gift_name=gift_name ) if not data: return data current_gift_pool = data.get('level_one') current_second_gift_pool = data.get('level_two') gifts = data.get('gifts') current_gift = current_second_gift_pool[gift_name] if current_gift['count'] - gift_count < 0: raise NegativeNumberError('gift count can not nagative') current_gift['count'] -= gift_count current_second_gift_pool[gift_name] = current_gift current_gift_pool[second_level] = current_second_gift_pool gifts[first_level] = current_gift_pool self.__save(gifts, self.gift_json)
最后,再來定一個刪除獎品的方法
def __delete_gift(self, first_level, second_level, gift_name): data = self.__check_and_getgift( first_level=first_level, second_level=second_level, gift_name=gift_name ) if not data: return data current_gift_pool = data.get('level_one') current_second_gift_pool = data.get('level_two') gifts = data.get('gifts') delete_gifts = current_second_gift_pool.pop(gift_name) current_gift_pool[second_level] = current_second_gift_pool gifts[first_level] = current_gift_pool self.__save(gifts, self.gift_json) return delete_gifts
base.py總算搞完了,也是廢了不少功夫,下面來測試一下吧
先來試一下創建用戶
ok,沒有報錯,再來看一下user.json
成功寫入!
再來試一下修改用戶權限
ok!運行成功,看下有沒有修改成功
漂亮,沒毛病!
再來試一下修改狀態,由於狀態就兩種true和false,
所以定義方法的時候,只要調用,就反方向修改,所以也不用傳狀態值了,我可真聰明
沒毛病,檢查一下
成功!老閆666啊!!
好了,繼續測試獎品庫這一塊
先試下初始化,初始化這一塊沒設置入參,每次執行Base類會自動檢查一遍,如果json文件是空的就給初始化
ok!結構也進來了
下面開始添加獎品
哦報錯了,檢查下為啥子
哦原來是入參count我設定了對比,只有int類型才可以,看來后面要加個校驗,修改下入參再試下
okk!修改后沒問題了,成功把老閆的臭腳加入獎品庫
后面還有幾個方法就不一一測試了
主要是寫累了,不想寫了
好了,本次就先這樣了,admin和user模塊下次再發,讓我好好思考思考!
最后附上本次的代碼!
# coding:utf-8 import os import time import json from common.utils import check_file, timestamp_to_string from common.error import (UserExistsError, RoleError, LevelError, NegativeNumberError, CountError) from common.consts import ROLES, FIRSTLEVELS, SECONDLEVELS class Base(object): def __init__(self, user_json, gift_json): self.user_json = user_json self.gift_json = gift_json self.__check_user_json() self.__check_gift_json() self.__init_gift() # 判斷user_json文件的類型以及地址 def __check_user_json(self): check_file(path=self.user_json) # 判斷gift_json文件的類型以及地址 def __check_gift_json(self): check_file(path=self.gift_json) # 讀取user文件,並解碼為字典格式 def __read_user(self, time_to_str=False): with open(self.user_json, 'r') as f: data = json.loads(f.read()) # 把文件的時間戳改為字符串格式 if time_to_str is True: for k, v in data.items(): v['create_time'] = timestamp_to_string(v['create_time']) v['update_time'] = timestamp_to_string(v['update_time']) data[k] = v return data # 寫入user信息 def __write_user(self, **user): # 判斷入參是否合規,是否包含username和role if "username" not in user: raise ValueError('missing username') if "role" not in user: raise ValueError('missing role') user['active'] = True user['create_time'] = time.time() user['update_time'] = time.time() user['gifts'] = [] users = self.__read_user() # 如果username已經存在了,那就拋出異常 if user['username'] in users: raise UserExistsError('username: %s had exists' % user['username']) # 如果username不存在,那就寫入文件 users.update( {user['username']: user} ) # 轉碼為json,並寫入 self.__save(data=users, path=self.user_json) # 修改role字段 def __change_role(self, username, role): users = self.__read_user() user = users.get(username) if not user: return False # 判斷入參role是否符合規范 if role not in ROLES: raise RoleError('not use role: %s' % role) user['role'] = role user['update_time'] = time.time() users[username] = user self.__save(data=users, path=self.user_json) return True # 修改active字段 def __change_active(self, username): users = self.__read_user() user = users.get(username) if not user: return False user['active'] = not user['active'] user['update_time'] = time.time() users[username] = user self.__save(data=users, path=self.user_json) return True # 刪除用戶 def __delete_user(self, username): users = self.__read_user() user = users.get(username) if not user: return False delete_user = users.pop(username) self.__save(data=users, path=self.user_json) return delete_user # 讀取獎品文件內容 def __red_gift(self): with open(self.gift_json, 'r') as f: data = json.loads(f.read()) return data # 獎品結構初始化 def __init_gift(self): data = { 'level1': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level2': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level3': { 'level1': {}, 'level2': {}, 'level3': {} }, 'level4': { 'level1': {}, 'level2': {}, 'level3': {} } } gifts = self.__red_gift() if len(gifts) != 0: return self.__save(data=data, path=self.gift_json) def __check_and_getgift(self, first_level, second_level, gift_name): if first_level not in FIRSTLEVELS: raise LevelError('first level not exists: %s' % first_level) if second_level not in SECONDLEVELS: raise LevelError('second level not exists: %s' % second_level) gifts = self.__red_gift() level_one = gifts[first_level] # 獲取level的對象"level1": {"level1": {}, "level2": {}}, "level3": {}} level_two = level_one[second_level] # 獲取level2的對象"level2": {} if gift_name not in level_two: return False return { 'level_one': level_one, 'level_two': level_two, 'gifts': gifts } # 定義一個寫入的函數 def __save(self, data, path): json_data = json.dumps(data) with open(path, 'w') as f: f.write(json_data) # 添加獎品到gift_json文件 def __write_gift(self, first_level, second_level, gift_name, gift_count): if first_level not in FIRSTLEVELS: raise LevelError('first level not exists: %s' % first_level) if second_level not in SECONDLEVELS: raise LevelError('second level not exists: %s' % second_level) gifts = self.__red_gift() current_gift_pool = gifts[first_level] # 獲取level的對象"level1": {"level1": {}, "level2": {}}, "level3": {}} current_second_gift_pool = current_gift_pool[second_level] # 獲取level2的對象"level2": {} # 如果傳入的count小於等於0,那就默認count為1 if gift_count <= 0: gift_count = 1 # 如果添加的獎品已經存在獎品庫,那么就把添加的商品庫存+1 if gift_name in current_second_gift_pool: current_second_gift_pool[gift_name]['count'] = current_second_gift_pool[gift_name]['count'] + gift_count else: # 如果添加的商品不在獎品庫,那就把獎品寫入文件 current_second_gift_pool[gift_name] = { 'name': gift_name, 'count': gift_count } # 還原level2的文件內容 current_gift_pool[second_level] = current_second_gift_pool # 還原level1的文件內容 gifts[first_level] = current_gift_pool # 編碼為json以及寫入json文件 self.__save(data=gifts, path=self.gift_json) # 修改獎品count數量 def __update_gift(self, first_level, second_level, gift_name, gift_count): data = self.__check_and_getgift( first_level=first_level, second_level=second_level, gift_name=gift_name ) if not data: return data current_gift_pool = data.get('level_one') current_second_gift_pool = data.get('level_two') gifts = data.get('gifts') current_gift = current_second_gift_pool[gift_name] if current_gift['count'] - gift_count < 0: raise NegativeNumberError('gift count can not nagative') current_gift['count'] -= gift_count current_second_gift_pool[gift_name] = current_gift current_gift_pool[second_level] = current_second_gift_pool gifts[first_level] = current_gift_pool self.__save(gifts, self.gift_json) def __delete_gift(self, first_level, second_level, gift_name): data = self.__check_and_getgift( first_level=first_level, second_level=second_level, gift_name=gift_name ) if not data: return data current_gift_pool = data.get('level_one') current_second_gift_pool = data.get('level_two') gifts = data.get('gifts') delete_gifts = current_second_gift_pool.pop(gift_name) current_gift_pool[second_level] = current_second_gift_pool gifts[first_level] = current_gift_pool self.__save(gifts, self.gift_json) return delete_gifts if __name__ == "__main__": gift_path = os.path.join(os.getcwd(), 'storage', 'gift.json') user_path = os.path.join(os.getcwd(), 'storage', 'user.json') a = Base(user_json=user_path, gift_json=gift_path) a.write_gift(first_level='level1', second_level='level1', gift_name='老閆的臭腳', gift_count=1000)
下面的是我自定義的異常類型,上面代碼有用的,一塊貼出來吧:
# coding:utf-8 """ 自定義異常方法 """ # 自定義路徑不存在異常 class NotPathError(Exception): def __init__(self, message): self.message = message # 自定義文件格式不正確異常 class FormatError(Exception): def __init__(self, message): self.message = message # 自定義是否是文件類型異常 class NotFileError(Exception): def __init__(self, message): self.message = message class UserExistsError(Exception): def __init__(self, message): self.message = message class RoleError(Exception): def __init__(self, message): self.message = message class LevelError(Exception): def __init__(self, message): self.message = message class NegativeNumberError(Exception): def __init__(self, message): self.message = message class NotUserError(Exception): def __init__(self, message): self.message = message class UserActiveError(Exception): def __init__(self, message): self.message = message class CountError(Exception): def __init__(self, message): self.message = message