Python之 -- 抽獎系統的開發(一)


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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM