python项目——ATM、购物车


前言

经过一段时间学习,掌握了不少python基础,今天要写的项目是登录注册购物三种功能的小项目。(由于结构简单并没有上传git)


一、项目开发功能模块划分

功能
core注册、登录、购物核心功能
data存放注册的用户数据、商品信息
public存放编写的方法文件
log存放日志文件
config存放配置文件

二、开发环境及其版本

没有写版本的对应是python3.7的

开发环境版本
python3.7
json
sys
os
time
hashlib
logging
re

在这里插入图片描述


三、core包

1.register模块

对于核心功能首先是注册需要注意以下几点:

  1. 用户名是否已被别的用户注册
  2. 密码与确认密码是否一致,密码长度是否在6到18位开头为大小写字母
  3. 注册时通过邀请要来确定注册的用户是管理员还是普通用户
  4. 不同类型用户密码加密方式不一样
  5. 注册成功时会生成对应数据放在user.txt中

其中registerM为用户界面函数相当于前端
而regUser便是业务逻辑层代码
后期可以将界面函数转移替换成对应的前端接口

from public.tools import *
from data.db_func import *

def registerM():
    print("用户注册")
    username = input("请输入用户名:").strip()
    password1 = input("请输入密码(密码开头必须是字母长度6到18位,可以使数字字母下划线):").strip()
    password2 = input("请再次输入密码:").strip()
    is_superuser = input("请输入邀请码(可不输入,输入后可注册为管理员)邀请码(hao123):").strip()
    regUser(username, password1, password2, is_superuser, "注册")

def regUser(username, password1, password2, is_superuser, str):
    # 获取所有用户
    users = get_users()
    is_superuser1 = False
    # 先比对是否存在该用户名
    file = chain_file(two_last_file(), "data", "user.txt")
    usernames = get_username(read_txt(file))
    if username in usernames:
        print("该用户名已被注册")
        return
    else:
        # 俩次密码是否一致,是否符合密码设置规则,是否以大小写字母开头包含字母数字下划线且6~18位组合
        if password1 == password2:
            if rightful_password(password1) != None:
                # 根据用户权限设置密码加密方式
                if is_superuser == "hao123":
                    is_superuser1 = True
                    password3 = encrypt_salt_md5(password1)
                else:
                    is_superuser1 = False
                    password3 = encrypt_md5(password1)
                user = {"username":username, "password":password3, "money": 0, "is_superuser":is_superuser1, "is_shd":False, "shop_car":{}}
                users.append(user)
                write_txt(USER_FILE,users)
                print("%s成功,2秒后将返回主界面"%str)
                time.sleep(2)
            else:
                print("密码不符合规定")
                registerM()
        else:
            print("俩次密码不一致")
            registerM()


if __name__ == '__main__':
    registerM()

2.login模块

登录模块注意以下几点:

  1. 登录时用户名是否存在于user.txt(类似数据库)
  2. 密码是否与用户文件中的一致(此处需要判断用户权限类型用不同的加密方法来判断密码)
  3. 用户是否被拉黑

其中loginM为用户界面函数相当于前端
而login便是业务逻辑层代码
后期可以将界面函数转移替换成对应的前端接口

from public.tools import *
from data.db_func import *

def loginM():
    print("登录")
    username = input("请输入用户名:")
    password = input("请输入密码:")
    login(username, password)

def login(username, password):
    # 读取对应用户密码及其权限
    password1 = get_user_password(username)
    is_superuser = get_user_isSuperuser(username)
    # 判断用户是否被拉黑
    users = get_users()
    for u in users:
        if u["username"] == username:
            if u["is_shd"]:
                print("用户已被拉黑无法登陆")
                time.sleep(2)
                return
    # 判断是否存在该用户
    # 先比对是否存在该用户名
    file = chain_file(two_last_file(), "data", "user.txt")
    usernames = get_username(read_txt(file))
    if username in usernames:
        # 先判断用户权限类型再判断用户输入的密码和已有密码是否一致
        if is_superuser:
            if password1 == encrypt_salt_md5(password):
                add_cookie(username, is_superuser)
                print("登陆成功")
            else:
                print("密码或用户名错误")
                loginM()
        else:
            if password1 == encrypt_md5(password):
                add_cookie(username, is_superuser)
                print("登陆成功")
            else:
                print("密码或用户名错误")
                loginM()
    else:
        print("密码或用户名错误")
        loginM()

if __name__ == '__main__':
    loginM()

3.shop模块

购物模块注意以下几点:

  1. 购买物品时是否加还是减
  2. 物品数量为0时从购物车删除
  3. 物品从无到有时添加
  4. 结算购物车时如果扣费需要清空购物车,不够时给予提示
    其中shopM为用户界面函数相当于前端
    而add_shop、settle_shop便是业务逻辑层代码
    后期可以将界面函数转移替换成对应的前端接口
from public.tools import *
from data.db_func import *

@user_is_login
def shopM():
    print("购物界面")
    print("1.购买商品")
    print("2.结算购物车")
    print("0.返回主界面")
    key1 = input("请选择需要的功能:").strip()
    commoditys = load_commdity()
    users = get_users()
    username = COOKIE["user"]["username"]
    if key1.isdigit() and re.search("[0-2]?",key1):
        key = int(key1)
        if key == 1:
            add_shop(commoditys, users, username)
            shopM()
        elif key == 2:
            settle_shop(users, username)
            shopM()
        else:
            print("返回主界面")
    else:
        print("请输入正确的功能序号")
        shopM()

def add_shop(commoditys, users, username):
    for u in users:
        if u["username"] == username:
            u["shop_car"]
            show_conndity()
            commodity_name = input("请输入需要的商品:")
            price = commoditys[commoditys.index(commodity_name) + 1]
            if commodity_name in commoditys:
                sc1 = input("请输入购买的数量:")
                if is_sum(sc1):
                    num = int(sc1)
                    if commodity_name in u["shop_car"]:
                        if num > 0:
                            u["shop_car"][commodity_name][0] += num  # 添加或减少到购物车操作
                            print("购物车:", u["shop_car"])
                            write_txt(USER_FILE,users)
                            time.sleep(2)
                        elif u["shop_car"][commodity_name][0] + num > 0:
                            u["shop_car"][commodity_name][0] = u["shop_car"][commodity_name][0] + num
                            print("购物车:", u["shop_car"])
                            write_txt(USER_FILE,users)
                            time.sleep(2)
                        elif u["shop_car"][commodity_name][0] + num == 0:
                            del u["shop_car"][commodity_name]
                            print("购物车:",u["shop_car"])
                            write_txt(USER_FILE,users)
                            time.sleep(2)
                        else:
                            print("购物车中数量不足或不存在,无法减少该商品数量")
                    else:
                        u["shop_car"][commodity_name] = [num, price]
                        write_txt(USER_FILE,users)
                        time.sleep(2)
                else:
                    print("购买数量必须为整数")
            else:
                print("不能购买不存在的商品")

def settle_shop(users, username): #结算购物车
    for u in users:
        if u["username"] == username:
            shop_list = u["shop_car"]
            user_money = u["money"]
            if len(shop_list) == 0:
                print("你还没有购物快去购物一番吧")
            else:
                shop_list_value = shop_list.values()
                sum = 0
                for i in shop_list_value:
                    sum += int(i[0]) * int(i[1])
                if u["money"] >= sum:
                    u["money"] -= sum
                    u["shop_car"].clear()
                    print("本次你消费了%d¥,账户余额:%d¥,欢迎下次再来" %(sum, u["money"]))
                    write_log("消费", "%s用户消费%d元"%(username, sum))
                    write_txt(USER_FILE, users)
                else:
                    print("你的余额不足,请尽快充值")

# 获取商品信息
def load_commdity():
    file = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data", "commodity.txt")
    with open(file, "r", encoding="utf8") as c:
        commditys = json.loads(c.read())
    return commditys

# 展示商品
def show_conndity():
    commoditys = load_commdity()
    k = 0
    for i in commoditys:
        if k % 2 == 0:
            print("商品:", i)
        else:
            print("单价:", i)
        k += 1



四、user包

用户模块注意以下几点:

  1. 查询余额功能只需要从用户数据中获取
  2. 充值功能是向用户余额进行充值
  3. 提现是从余额中提取现金到卡中(由于本项目没有设计银行卡所以改为直接扣除,扣除数额必须在余额以内)
  4. 转账是用户从余额转移部分资金到另一个用户的余额
  5. 流水查看需要统计日志中该用户消费情况(为了加深日志的使用采取从日志中获取)
  6. 拉黑用户需要先判断是否有权限,然后修改对应用户的拉黑属性
  7. 删除用户需要先判断是否有权限,然后删除对应用户数据
  8. 新增用户需要先判断是否有权限,然后添加对应用户数据(此处可使用注册功能快速实现)
    其中userM、user_func为用户界面函数相当于前端
    而其余8个函数便是业务逻辑层代码
    后期可以将界面函数转移替换成对应的前端接口
from public.tools import *
from core.register import regUser
from data.db_func import *
import re

@user_is_login
def userM():
    print("用户界面")
    username = COOKIE["user"]["username"]
    is_superuser = COOKIE["user"]["is_superuser"]
    user_func(is_superuser)
    key1 = input("请选择功能:").strip()
    if key1.isdigit() and re.search("[0-8]?",key1):
        key = int(key1)
        if key == 1:
            select_money(username)
            userM()
        elif key == 2:
            charge(username)
            userM()
        elif key == 3:
            get_card(username)
            userM()
        elif key == 4:
            give_money(username)
            userM()
        elif key == 5:
            select_expense(username)
            userM()
        elif key == 6:
            forbid_user()
            userM()
        elif key == 7:
            del_user()
            userM()
        elif key == 8:
            add_user()
            userM()
        else:
            print("返回主界面")
    else:
        print("请输入正确的功能序号")
        userM()


# 用户功能模块
def user_func(is_superuser):
    func = ["余额查询", "充值", "提现", "转账", "流水查看", "拉黑用户", "删除用户", "新增用户"]
    if is_superuser:
        for f, k in enumerate(func, start=1):
            print("%d、%s"%(f, k))
        print("0、返回")
    else:
        for f, k in enumerate(func, start=1):
            if f != "拉黑用户":
                print("%d、%s"%(f, k))
        print("0、返回")

# 余额查询
def select_money(username):
    print("用户:%s,余额:%d"%(username, get_user(username)["money"]))

# 充值
def charge(username):
    print("充值界面")
    select_money(username)
    money = input("请输入充值金额(0起步整数充值):").strip()
    users = get_users()
    if money.isdigit():
        for u in users:
            if u["username"] == username:
                u["money"] += int(money)
                write_txt(USER_FILE,users)
                print("充值成功")
                select_money(username)
                write_log("充值", "%s用户充值%d元" % (u["username"], int(money)))
                time.sleep(2)
    else:
        print("充值金额请输入大于0的整数")
        charge(username)

# 提现
def get_card(username):
    print("提现界面")
    select_money(username)
    money = input("请输入提现金额(0起步整数充值):").strip()
    users = get_users()
    if money.isdigit():
        for u in users:
            if u["username"] == username:
                if u["money"] >= int(money):
                    u["money"] -= int(money)
                    write_txt(USER_FILE, users)
                    print("提现成功")
                    select_money(username)
                    write_log("提现", "%s用户提现%d元" %(u["username"], u["money"]))
                    time.sleep(2)
                else:
                    print("余额不足无法提现")
                    get_card(username)
    else:
        print("提现金额请输入大于0的整数")
        get_card(username)

# 转账
def give_money(username):
    print("转账界面")
    select_money(username)
    username1 = input("请输入转账对象用户名:").strip()
    money = input("请输入提现金额(0起步整数充值):").strip()
    users = get_users()
    if money.isdigit():
        for u in users:
            if u["username"] == username:
                if u["money"] >= int(money):
                    if username1 in get_username(users):
                        for u1 in users:
                            if u1["username"] == username1:
                                u1["money"] += int(money)
                                u["money"] -= int(money)
                                write_txt(USER_FILE, users)
                                print("转账成功")
                                write_log("转账", "%s用户向%s用户转账%d元" %(u["username"], u1["username"], int(money)))
                                select_money(username)
                                time.sleep(2)
                    else:
                        print("转账用户名错误")
                        give_money(username)
                else:
                    print("你的余额不足,无法转账")
                    give_money(username)
    else:
        print("转账金额请输入大于0的整数")
        get_card(username)

# 流水查看
def select_expense(username):
    print("流水查看")
    with open(LOGFILE_PATH, "r", encoding="utf8") as f:
        data = f.read()
    data1 = re.findall(username + "用户消费.*元", data)
    data2 = []
    for d in data1:
        data2.append(re.findall("[0-9]+", d))
    sum = 0
    for k in data2:
        sum += int(k[0])
    print("%s用户共消费了%d元"%(username, sum))

# 拉黑用户
def forbid_user():
    print("拉黑用户界面")
    print("拉黑后的用户无法登陆")
    users = get_users()
    usernames = get_username(users)
    print("系统中所有的用户:", usernames)
    username = input("请输入需要拉黑的用户名").strip()
    if username in usernames:
        for u in users:
            if u["username"] == username:
                u["is_shd"] = True
                write_txt(USER_FILE, users)
                print("拉黑成功")
                write_log("拉黑用户", "拉黑了%s用户"%username)
                time.sleep(2)
    else:
        print("没有该用户")
        forbid_user()

# 删除用户
def del_user():
    print("删除用户界面")
    users = get_users()
    usernames = get_username(users)
    print("系统中所有的用户:", usernames)
    username = input("请输入需要删除的用户名:").strip()
    if username in usernames:
        i = 0
        for u in users:
            if u["username"] == username:
                del users[i]
                write_txt(USER_FILE, users)
                print("删除成功")
                write_log("删除用户", "删除了%s用户"%username)
                time.sleep(2)
            i += 1
    else:
        print("没有该用户")
        forbid_user()

# 添加用户
def add_user():
    users = get_users()
    usernames = get_username(users)
    print("系统中所有的用户:", usernames)
    username = input("请输入需要添加的用户名").strip()
    password = input("请输入需要添加的密码").strip()
    is_superuser = input("请输入需要添加的用户是否为管理员(输入1为是,不输入为否)").strip()
    if is_superuser == "1":
        is_superuser = "hao123"
    regUser(username, password, password, is_superuser, "添加")
    write_log("添加用户", "添加了用户名:%s"%username)
    users = get_users()
    usernames = get_username(users)
    print("系统中所有的用户:", usernames)
    time.sleep(2)

if __name__ == '__main__':
    select_expense("kdq")


五、data包

该包用于存放用户数据文件和商品信息,以及对数据库操作的代码

from config.setting import *
from public.tools import write_txt, read_txt
# 不存在user.txt时自动生成user.txt文件

def auto_user():
    open(USER_FILE, "w+")
    data = []
    write_txt(USER_FILE, data)
    return read_txt(USER_FILE)

# 获取所有用户名
def get_username(data):
    users = []
    for u in data:
        users.append(u["username"])
    return users

# 获取所有用户数据
def get_users():
    try:
        return read_txt(USER_FILE)
    except Exception:
        return auto_user()

# 获取对应用户数据
def get_user(username):
    try:
        users = get_users()
        for u in users:
            if u["username"] == username:
                return u
            return []
    except Exception:
        return auto_user()

# 获取对应用户权限
def get_user_isSuperuser(username):
    user = get_user(username)
    if user:
        return user["is_superuser"]

# 获取对应用户的密码
def get_user_password(username):
    user = get_user(username)
    if user:
        return user["password"]

用户文本
{“username”:username, “password”:password, “money”:money, “is_superuser”:True, “is_shd”:True, “shop_car”:{“shop_name”:[num, price]} }

商品文本
[“梨子”,10, “苹果”,5, “只狗key”,198, “一只贝爷”,998, “水果手机”,6999, “蔡虚鲲”,114514]


六、public包

该包用于存放一些方法,编写方法可以让文件可读性提高、降低不重要代码对核心算法的干扰

import json
import re
import hashlib
import time
import logging
import logging.config

from config.setting import *

# 获取执行文件上一级目录
def last_file():
    return os.path.dirname(__file__)

# 获取执行文件上一级目录的根目录
def two_last_file():
    return os.path.dirname(os.path.dirname(__file__))

# 拼接路径
def chain_file(*args, **kwargs):
    return os.path.join(*args, **kwargs)

# 读取txt文件内容
def read_txt(file):
    with open(file, "r", encoding="utf8") as f:
        return json.loads(f.read())

# 保存txt文件
def write_txt(file, data):
    with open(file, "w", encoding="utf8") as f:
        f.write(json.dumps(data))



# 验证密码是否符合规则
def rightful_password(password):
    condition = re.compile("^[a-zA-Z]\w{5,17}$")
    return re.search(condition, password)

# md5加密
def encrypt_md5(password):
    md5 = hashlib.md5()
    md5.update(password.encode("utf8"))
    return md5.hexdigest()

# md5加盐加密
def encrypt_salt_md5(password):
    md5 = hashlib.md5("superuser".encode("utf8"))
    md5.update(password.encode("utf8"))
    return md5.hexdigest()

# 登录后记录cookie
def add_cookie(username, is_superuser):
    COOKIE["user"] = {"username":username, "is_superuser":is_superuser}

# 不存在log文件夹时自动生成log文件夹
def auto_log():
    file = os.path.join(os.path.dirname(os.path.dirname(__file__)), "log")
    if not os.path.isdir(file):
        os.makedirs(file)

# 记录日志
def write_log(func, content):
    auto_log()
    logging.config.dictConfig(LOGGING_DIC)  # 自动加载字典中的配置
    logger1 = logging.getLogger(func)
    logger1.debug(content)

from core import login
# 是否登录装饰器
def user_is_login(func):
    def inner(*args, **kwargs):
        try:
            if COOKIE["user"] != None:
                res = func(*args, *kwargs)
                return res
        except Exception:
            print("没有登陆,请先登录再操作")
            print("2秒后跳转到登录界面界面")
            time.sleep(2)
            login.loginM()
    return inner

# 判断输入是否为正数或负数
def is_sum(str):
    try:
        k = int(str)
        return isinstance(k, int)
    except ValueError:
        return True

if __name__ == '__main__':
    pass

七、config包

包中的setting模块用于存放一些很少变动的固定内容,其中包含了用户数据文件路径、日志配置字典

import os

COOKIE = {}

USER_FILE = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data", "user.txt")

# 自定义文件路径
LOGFILE_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "log", "log.txt")

# 定义日志输出格式 开始
STANDARD_FORMAT = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                  '[%(levelname)s][%(message)s]'

# log配置字典
LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format': STANDARD_FORMAT
        }
    },
    'filters': {},  # 过滤日志
    'handlers': {
        #打印到终端的日志
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到屏幕
            'formatter': 'standard'
        },
        #打印到文件的日志,收集info及以上的日志
        'default': {
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
            'formatter': 'standard',
            'filename': LOGFILE_PATH,  # 日志文件
            'maxBytes': 1024*1024*5,  # 日志大小 5M
            'backupCount': 5,
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
        },
    },
    'loggers': {
        #logging.getLogger(__name__)拿到的logger配置
        '': {
            'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)传递
        }
    },
}



八、start

start模块用于启动软件

import re
from core import login, register, shop, user

def startM():
    print("主界面")
    print("1.用户登录")
    print("2.用户注册")
    print("3.购物")
    print("4.用户管理")
    print("0.退出程序")
    key1 = input("请选择功能:").strip()
    if key1.isdigit() and re.search("[0-4]?",key1):
        key = int(key1)
        if key == 1:
            login.loginM()
            startM()
        elif key == 2:
            register.registerM()
            startM()
        elif key == 3:
            shop.shopM()
            startM()
        elif key == 4:
            user.userM()
            startM()
        else:
            print("退出软件")
    else:
        print("输入错误")
        startM()

if __name__ == '__main__':
    startM()

总结

目前项目划分比较合理,将整个项目分为了三个部分表现层、业务逻辑层、数据持久层,由于没有使用前端和数据库只能大致模拟这样的效果,项目分割后方便协作开发、产生异常时也不会项目影响。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值