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
复制代码
posted @   隔壁老闫  阅读(346)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示