第十六章 购物车系统完整

购物车完整

1.项目需求

业务逻辑功能

"1":登录
"2":注册
"3":查看余额
"4":转账
"5":存款
"6":取款
"7":查看流水
"8":购物
"9":查看购买商品
"10":注销

2.一个完整的项目

我们上节课讲了模块

介绍了模块的优势:

​ 1.程序的组织结构更加清晰

​ 2.维护起来更加方便

​ 3.模块可以被重复使用

​ 4.提高了程序员的开发效率

这节课老师就通过这个购物车系统来证明这些优势

需要有的模块目录

运行启动目录文件
    bin
        start.py
配置文件
	conf
		setting.py
执行任务文件
	core
		src.py
数据存储目录
	db
		db_handle.py
业务逻辑接口
	interface
		bank.py
		shop.py
		user.py
公用逻辑接口
	lib
		common.py
历史日志记录
	log
		user1.log

那么我们来创建一下项目

1.第一种以shoppingcart为根目录

第一种导入模块不会报红色波浪线

1655293688518

2.第二种不以shoppingcart为根目录创建

第二种导入模块会报红色波浪线,对程序没影响但是会影响效率

1655293974248

第二种报红色波浪线的解决办法

将文件夹Mark Directory as成source root的方法

pycharm标记成项目路径来源文件夹

1655294302235

文件夹变成蓝色

1655294356781

3.代码编写流程

一.启动程序路径配置bin/start.py

1.拿到当前的项目执行目录

import sys
import os
# 拿到当前的执行路径
print(os.path.dirname(__file__))
Source_path = os.path.dirname(os.path.dirname(__file__))

print(Source_path)

2.添加到解释器的路径里面去

sys.path.append(Source_path)
# 添加到解释器路径当中
print(sys.path)

3.启动core/src.py文件run函数

from core import src

if __name__ == '__main__':
    src.run()
补充 __ name __
print(__name__)
# # start.py作为执行文件,当前文件作为主程序

1655360123558

运行其他文件比如spam.py
import start

1655360195221

我们看到运行自己print(__ name __ ) 结果是 __ main __ ,而把导入start.py 这个结果确实 start

所有我们就可以通过一个if判断的条件,来判断你的这个文件是不是主程序。

if __ name __ == '__ main __':
if __name__ == '__main__':# 的意思是:只有在本程序直接运行的情况下,才会执行某些操作。
    src.run()  

4.写run函数,通过序号选择相应的函数功能

def login():
    '''
    登录函数,密码输错三次锁定,用户名输错可以一直输入
    :return:
    '''
def register():
	print('注册')
def check_balance():
    print('查看余额')
def transfer():
    print('转账')
def repay():
    print('还款')
def withdraw():
    print('取款')
def check_record():
    print('查看流水')
def shopping():
    print('购物')
def look_shoppingcart():
    print('查看购物车')
fun_dic={'1':login,
         '2':register,
         '3':check_balance,
         '4':transfer,
         '5':repay,
         '6':withdraw,
         '7':check_record,
         '8':shopping,
         '9':look_shoppingcart,
         '10':loginout,
         }
def run():
    while True:
        print("""
    "1":登录
    "2":注册
    "3":查看余额
    "4":转账
    "5":还款
    "6":取款
    "7":查看流水
    "8":购物
    "9":查看购买商品
    "10":注销

        """)
        choice=input('输入操作编号').strip()
        
        if choice not in fun_dic:continue
        # fun_dic[choice]拿到函数内存地址,加括号调用
        fun_dic[choice]()

二.设置一个用户的信息,登录的状态

user_data={'name':None,
           'is_auth':False,}

三.注册register之1接口user.get_userinfo_by_name

def register():
    if user_data['is_auth']:
        print('你已登录')
        return
    print('注册')
    while True:
        name = input('输入用户名').strip()
        # 四
        # 查看用户是否已经注册需要用到接口interface  对应的  user
        user_dic = user.get_userinfo_by_name(name)
        #
        print(user_dic)

五.写一个查询用户信息的接口

def get_userinfo_by_name(name):
    '''
    写一个查询用户信息的接口
    :param name:
    :return:
    '''
    # 这里需要用到一个db 下面的 db_handle 数据管理的方法在这个文件夹下
    # 这里需要返回用户信息   ???
    return db_serialization.select(name)

六.查看用户信息接口,通过反序列化去查询

思路保存到db/db_handle.py

# 思路
# 1.路径在 conf/setting.py进行配置
# 2.有json模块,存储成序列化文件

假设已经注册了,我们读取序列化文件,也就是反序列化李老师.json

db_handle.py之1

import os
import json
from  conf import setting
class Serialization:
    def select(self,name):
        # 读取一个文件信息,我们需要什么?
        # 1.需要文件路径
        # 思路
        # 我们可以通过json文件名进行查询,
        # 如果查到文件存在,说明已经注册了,
        # 不存在,代表没注册
        #七 路径写道setting里面  ???
        path = r'%s/%s.json'%(setting.DB_path,name)
        # 有李老师这个json文件就返回,没有就返回False
        # 返回给谁  bank shop user 这个三个接口 都可能用的上
        if os.path.isfile(path):
            with open(path,'r',encoding='utf-8')as f:
                # 对序列化json文件操作load
                return json.load(f)
        else:
            return False
# 记得要实例化
db_serialization=Serialization()

七.setting.py

# @Author : 大海
# @File : setting.py

import os
# 拿到当前的执行路径
Source_path = os.path.dirname(os.path.dirname(__file__))

DB_path = os.path.join(Source_path,'db')

# 添加日志文件路径
LOG1_path=os.path.join(Source_path,'log','user1.log')

八.注册register之1接口user.register_user

def register():
    if user_data['is_auth']:
        print('你已登录')
        return
    print('注册')
    while True:
        name = input('输入用户名').strip()
        # 四
        # 查看用户是否已经注册需要用到接口interface  对应的  user
        user_dic = user.get_userinfo_by_name(name)
        #
        print(user_dic)
        if not user_dic:
            pwd = input('输入密码').strip()
            pwd1 = input('确认密码').strip()
            if pwd == pwd1:
                # 八
                user.register_user(name,pwd)
                break
            else:
                print('2次密码不一致')
        else:
            print('用户名已经存在')

九.注销拼接的字典进行序列化注册

register_user接口1

def register_user(name,password,balance=15000):
    '''
    注册用户接口
    :param name:
    :param password:
    :param balance:
    :return:
    '''
    # 信息传入定义的字典
    user_dic = {'name': name, 'password': password, 'locked': False, 'account': balance, 'shopping_cart': {}, 'bankflow': []}
    # 这个字典到时候会存储成json文件
    # 需要通过谁写入    ???
    # db包  db_handle模块 的 db_serialization 对象的方法
    # db_serialization
    db_serialization.update(user_dic)

db_handle.py之2

import os
import json
from  conf import setting
class Serialization:



    def select(self,name):
        # 读取一个文件信息,我们需要什么?
        # 1.需要文件路径
        # 思路
        # 我们可以通过json文件名进行查询,
        # 如果查到文件存在,说明已经注册了,
        # 不存在,代表没注册
        # 路径写道setting里面  ???
        path = r'%s/%s.json'%(setting.DB_path,name)
        # 有ljy这个json文件就返回,没有就返回False
        # 返回给谁  bank shop user 这个三个接口 都可能用的上
        if os.path.isfile(path):
            with open(path,'r',encoding='utf-8')as f:
                # 对序列化json文件操作load
                return json.load(f)
        else:
            return False
    # 十.序列化存储用户信息
    def update(self,user_dic):
        # 拿到 # 路径
        path_file = os.path.join(setting.Source_path,'db','%s.json'%user_dic['name'])
        # 注册是利用json文件名注册
        with open(path_file, 'w', encoding='utf-8') as f:
            #  对序列化json文件操dump
            json.dump(user_dic, f)
            # 刷新
            f.flush()
# 记得要实例化
db_serialization=Serialization()

register_user接口2之添加日志

def register_user(name,password,balance=15000):
    '''
    注册用户接口
    :param name:
    :param password:
    :param balance:
    :return:
    '''
    # 信息传入定义的字典
    user_dic = {'name': name, 'password': password, 'locked': False, 'account': balance, 'shopping_cart': {}, 'bankflow': []}
    # 这个字典到时候会存储成json文件
    # 需要通过谁写入    ???
    # db包  db_handle模块 的 db_serialization 对象的方法
    # db_serialization
    db_serialization.update(user_dic)
    print('%s 注册了' % name)
    # 十一 调用日志的接口 common存储
    # 存储一个日志
    # 日志是公用的 在lib 文件夹 common 写方法 数据存储到 log 文件夹里面
    # 需要添加log 下面日志文件的路径到 setting 里面
    common.log('%s 注册了' % name)

十二.日志写入数据方法

def log(msg):
    # 当前时间年月日时分秒
    current_time = time.strftime('%Y-%m-%d %X')
    with open(setting.LOG1_path, 'a', encoding='utf-8') as f:
        f.write(current_time + '-' * 5 + msg + '\n')

十三.login

import time
def login():
    '''
    登录函数,密码输错三次锁定,用户名输错可以一直输入
    :return:
    '''
    if user_data['is_auth']:
        print('你已登录')
        return
    print('请登录')

    count = 0
    while True:
        name = input('输入用户名').strip()
        # 九
        # 需要查询是否用户存在
        # 省了多少代码
        user_dic = user.get_userinfo_by_name(name)
        if user_dic:
            # 是否锁定
            print(user_dic['locked'])
            # 先写锁定
            if user_dic['locked']:
                # 十四 解锁接口
                # 需要的解锁定 写入 user_dic  locked 变 True  写入 json数据修改
                time.sleep(5)
                user.unlock_user(name)
                count = 0
                continue
            pwd = input('输入密码').strip()
            if user_dic['password'] == pwd and not user_dic == user_dic['locked']:
                user_data['name'] = name
                user_data['is_auth'] = True
                print('登录成功')
                break
            else:
                print('密码错误')
                count += 1
            if count >= 3:
                # 十三。锁定接口
                # 需要的是锁定 写入 user_dic  locked 变 True  写入 json数据修改
                user.lock_user(name)
        else:
            print('用户名不存在')

十四.锁定和解锁接口

def unlock_user(name):
    '''
    解锁用户接口
    :param name:
    :return:
    '''
    # 拿到用户的信息
    user_dic = get_userinfo_by_name(name)
    user_dic['locked'] = False
    db_serialization.update(user_dic)
    print('已经解锁')
    common.log('已经解锁')


def lock_user(name):
    '''
    解锁用户接口
    :param name:
    :return:
    '''
    # 拿到用户的信息
    user_dic = get_userinfo_by_name(name)
    user_dic['locked'] = True
    db_serialization.update(user_dic)
    print('已被锁定')
    # 记录日志
    common.log('已被锁定').锁定和解锁接口

十五.查看余额

src.py未加登录装饰器

def check_balance():
    print('查看余额')
#     需要 interface 接口 bank.py 模块 check_balance_interface方法
#     # 传入登录名字调用接口加工字典account对应的value余额
    balance = bank.check_balance_interface(user_data['name'])
    print('你的余额为%s' % balance)

bank.py返回user_dic['account']

def check_balance_interface(name):
    '''
            查看余额接口
            :param name:
            :return:
            '''
    print('%s 查看了余额' % (name))
    common.log('%s 查看了余额' % name)
    # 思考逻辑 , 后面代码不用管了 一条龙服务
    user_dic=user.get_userinfo_by_name(name)
    return user_dic['account']

十六.其他功能添加装饰器:common里面添加login_intter装饰器

def login_intter(func):
    '''
        func就是它们
        '3':check_balance,
        '4':transfer,
        '5':repay,
        '6':withdraw,
        '7':check_record,
        '8':shopping,
        '9':look_shoppingcart,
        '10':loginout,
        都要在登录的情况下才能执行
        全部都写一个登录装饰器
        公用的在common里面写
        '''
    def wrapper():
        if not src.user_data['is_auth']:# 非登录就满足条件
            src.login()
        else:# 已经登录就不满足条件
            func()
    return wrapper

查看余额添加装饰器

@common.login_intter
def check_balance():
    print('查看余额')
#     需要 interface 接口 bank.py 模块 check_balance_interface方法
#     # 传入登录名字调用接口加工字典account对应的value余额
    balance = bank.check_balance_interface(user_data['name'])
    print('你的余额为%s' % balance)

十七.转账

需要3个接口:用户查询,查看余额,转账

get_userinfo_by_name,check_balance_interface,transfer_interface

@common.login_intter
def transfer():
    print('转账')
    while True:
        trans_name = input('请输入转入用户名,q返回退出转账').strip()
        if trans_name == user_data['name'] or trans_name == user_data['name'].upper():
            print('不能给自己转账')
            continue
        if 'q' == trans_name:
            break
        # 查看转账用户是否存在
        trans_dic = user.get_userinfo_by_name(trans_name)
        if trans_dic:
            trans_money = input('输入转账金额').strip()
            # 纯数字的字符串类型
            if trans_money.isdigit():
                trans_money = int(trans_money)
                if trans_money > 0:
                    # 调用查询余额接口,根据登录名拿到余额
                    user_balance=bank.check_balance_interface(user_data['name'])
                    # 用户的余额必须大于转入的钱
                    if user_balance > trans_money:
                        # 写转账接口 user_data['name'],trans_name,trans_money
                        bank.transfer_interface(user_data['name'], trans_name, trans_money)
                        break
                else:
                    print('不能为负数')
        else:
            print('用户不存在')

用户查询get_userinfo_by_name

def get_userinfo_by_name(name):
    '''
            写一个查询用户信息的接口
            :param name:
            :return:
    '''
    # 这里需要用到一个db 下面的 db_handle 数据管理的方法在这个文件夹下
    # 这里需要返回用户信息   ???
    return db_serialization.select(name)

查看余额check_balance_interface

def check_balance_interface(name):
    '''
            查看余额接口
            :param name:
            :return:
            '''
    print('%s 查看了余额' % (name))
    common.log('%s 查看了余额' % name)
    # 思考逻辑 , 后面代码不用管了 一条龙服务
    user_dic=user.get_userinfo_by_name(name)
    return user_dic['account']

转账transfer_interface

def transfer_interface(from_name, to_name, account):
    '''
            转账接口输入自己name,别人name,和钱
            :param from_name:
            :param to_name:
            :param account:
            :return:
    '''
    from_user_dic = user.get_userinfo_by_name(from_name)
    to_user_dic = user.get_userinfo_by_name(to_name)
    if from_user_dic['account'] >= account:  # 比较自己的钱和需要转入的钱
        from_user_dic['account'] -= account  # 自己的钱减
        to_user_dic['account'] += account  # 别人的钱加
        # 记录
        from_user_dic['bankflow'].extend(['%s 转账 %s 元 给 %s'%(from_name, account, to_name)])
        to_user_dic['bankflow'].extend(['%s 收到 %s 转账 %s'%(to_name, from_name, account)])
        # 写入json 更新用户转账数据
        db_serialization.update(from_user_dic)
        db_serialization.update(to_user_dic)
        common.log('%s 收到 %s 转账 %s' % (to_name, from_name, account))
        print('%s 向 %s 转账 %s' % (from_name, to_name, account))

    else:
        print('转账钱不够')

十八.存款

需要1个存款接口

@common.login_intter
def repay():
    print('存款')
    while True:
        account=input('请输入存款的金额,输入q退出').strip()
        if account == 'q': break
        if account.isdigit():
            account = int(account)
            if account > 0:
                # 调用存款接口执行存款的业务逻辑,传入用户名和存款金额
                bank.repay_interface(user_data['name'], account)
                break
            else:
                print('存款大于0')
        else:
            print('请输入数字')

存款接口repay_interface

def repay_interface(name,account):
    '''
            存款接口
            :param name:
            :param account:
            :return:
            '''
    # # 查询json用户获取用户字典
    user_dic = db_serialization.select(name)
    # 用户字典余额加上存款金额
    user_dic['account'] += account
    user_dic['bankflow'].append('%s 存入 %s 元' % (name, account))
    # # 写入json 更新用户存款数据
    db_serialization.update(user_dic)
    print('%s存款了%s' % (name, account))
    common.log('%s存款了%s' % (name, account))

十九.取款

需要2个接口:查看余额,取款

@common.login_intter
def withdraw():
    print('取款')
    while True:
        qukuan_money = input('请输入取款金额').strip()
        if 'q' == qukuan_money: break
        if qukuan_money.isdigit():
            qukuan_money = int(qukuan_money)
            if qukuan_money>0:
                # 调用查询余额接口,根据登录名拿到余额
                user_account = bank.check_balance_interface(user_data['name'])
                # 取款
                if user_account >= qukuan_money:
                    # 调用取款接口执行取款的业务逻辑,传入用户名和取款金额
                    bank.withdraw_interface(user_data['name'], qukuan_money)
                    print('取款%s元成功' % qukuan_money)
                    break
                else:
                    print('钱不够')
            else:
                print('取款金额需大于0')
        else:
            print('输入数字')

查看余额check_balance_interface

def check_balance_interface(name):
    '''
            查看余额接口
            :param name:
            :return:
            '''
    print('%s 查看了余额' % (name))
    common.log('%s 查看了余额' % name)
    # 思考逻辑 , 后面代码不用管了 一条龙服务
    user_dic=user.get_userinfo_by_name(name)
    return user_dic['account']

取款

def withdraw_interface(name,account):
    '''
        取款接口
        :param name:
        :param account:
        :return:
        '''
    # # 查询json用户获取用户字典
    user_dic = db_serialization.select(name)
    # 用户字典余额加上取款金额
    user_dic['account'] -= account
    user_dic['bankflow'].append('%s 取出 %s 元' % (name, account))
    # # 写入json 更新用户存款数据
    db_serialization.update(user_dic)
    print('%s取出了%s' % (name, account))
    common.log('%s取出了%s' % (name, account))

二十.查看流水

需要1个查看流水接口

@common.login_intter
def check_record():
    print('查看流水')
    # 调用查看流水接口执行查看流水的业务逻辑,传入用户名
    bankflow = bank.check_bankflow_interface(user_data['name'])
    # print(bankflow)
    for record in bankflow:
        print(record)

查看流水接口check_bankflow_interface

def check_bankflow_interface(name):
    '''
        银行流水接口
        :param name:
        :return:
        '''
    # # 查询json用户获取用户字典
    user_dic = db_serialization.select(name)
    common.log('%s 查看银行流水' % name)
    return user_dic['bankflow']

二十一.购物

需要2个接口:查看余额,购物

check_balance_interface,shopping_interface

@common.login_intter
def shopping():
    print('购物')
    goods_list = [
        ['coffe', 30],
        ['chicken', 20],
        ['iPhone', 8000],
        ['macBook', 12000],
        ['car', 100000]
    ]
    shopping_cart = {}
    # 调用查询余额接口,根据登录名拿到余额
    user_money = bank.check_balance_interface(user_data['name'])
    cost_money = 0
    while True:
        for i, item in enumerate(goods_list):
            print(i, item)
        choice = input('请输入购物编号').strip()
        if choice.isdigit():
            choice = int(choice)
            if choice < 0 or choice >= len(goods_list): continue
            goods_name = goods_list[choice][0]
            goods_price = goods_list[choice][1]
            if user_money >= goods_price:
                if goods_name in shopping_cart:  # 原来已经购买过
                    shopping_cart[goods_name]['count'] += 1
                    shopping_cart[goods_name]['price'] = shopping_cart[goods_name]['count'] * goods_price
                else:
                    shopping_cart[goods_name] = {'price': goods_price, 'count': 1}
                user_money -= goods_price
                cost_money += goods_price
                print('%s 新的购物商品' % goods_name)
            else:
                print('钱不够')
                continue
        elif choice == 'q':
            print(shopping_cart)
            buy = input('卖不卖 (y/n)>>:').strip()
            if buy == 'y':
                # 正常需要加密码验证
                if cost_money == 0: break
                # 三十
                # 调用购物接口,传入用户数据,购物车,花费金额
                shop_success=shop.shopping_interface(user_data['name'], shopping_cart, cost_money)
                if shop_success:
                    print('购买成功')
                    break
                else:
                    print('钱不够')
                    break
            else:
                print('不买')
                break
        else:
            print('非法输入')

查看余额check_balance_interface

def check_balance_interface(name):
    '''
            查看余额接口
            :param name:
            :return:
            '''
    print('%s 查看了余额' % (name))
    common.log('%s 查看了余额' % name)
    # 思考逻辑 , 后面代码不用管了 一条龙服务
    user_dic=user.get_userinfo_by_name(name)
    return user_dic['account']

购物shopping_interface

需要1个接口:花费接口

def shopping_interface(name, shopping_cart, cost_money):
    '''
            购物接口
            :param name:
            :param shopping_cart:
            :param cost_money:
            :return:
    '''
    # 需要消费进行扣款,那么这个应该和银行打交道 调用 bank 接口去做这件事情
    # 这个银行的接口要判断我的钱是否大于花费的钱
    # 是否扣款成功

    consum_success=bank.consum_interface(name,cost_money)
    if consum_success:
        # 保存购物车
        # 查询用户json字典
        user_dic =   user.get_userinfo_by_name(name)
        user_dic['shopping_cart'] = shopping_cart
        # 更新用户json字典
        db_serialization.update(user_dic)
        common.log('%s 花费 %s 购买了 %s' % (name, cost_money, shopping_cart))
        print('%s 花费 %s 购买了 %s' % (name, cost_money, shopping_cart))
        return True
    else:# 不能花费成功就不能购物成功
        return False

花费接口

def consum_interface(name, account):
    '''
        消费接口
        :param name:
        :param account:
        :return:
        '''
    # 查询用户json字典
    user_dic = user.get_userinfo_by_name(name)
    # 用户的钱和花费的钱进行比较
    if user_dic['account'] >= account:
        user_dic['account'] -= account
        # 添加到bankflow列表里面记录流水
        user_dic['bankflow'].extend(['%s 消费了 %s 元钱' % (name, account)])
        db_serialization.update(user_dic)
        common.log('%s 消费了 %s 元钱' % (name, account))
        print(('%s 消费 %s 元' % (name, account)))
        return  True

    else:
        return False

二十二.查看购物车

需要1个接口:查看购物车接口

@common.login_intter
def look_shoppingcart():
    print('查看购物车')
    # 调用查看购物车接口,传入用户名
    shopping_s = shop.check_shoppingcart(user_data['name'])
    print(shopping_s)

查看购物车check_shoppingcart

def check_shoppingcart(name):
    # 查询用户json字典
    user_dic = user.get_userinfo_by_name(name)
    print('%s 查看了购物车'%name)
    common.log('%s 查看了购物车' % name)
    return user_dic['shopping_cart']

4.一个完整的项目代码

start.py


import sys
import os
Source_path = os.path.dirname(os.path.dirname(__file__))
# D:/shopping_cartA8
# print(Source_path)

sys.path.append(Source_path)

# print(sys.path)


from core import src
#
#
# src.run()


# print(__name__)
# # start.py作为执行文件,当前文件作为主程序
# if __name__ == '__main__':的意思是:只有在本程序直接运行的情况下,才会执行某些操作。
if __name__ == '__main__':
    src.run()





setting.py

# @Author : 大海
# @File : setting.py

import os
Source_path = os.path.dirname(os.path.dirname(__file__))
# D:/shopping_cartA8
# D:/shopping_cartA8/db
# D:/shopping_cartA8\db
DB_path = os.path.join(Source_path,'db')
# print(DB_path)

LOG1_path=os.path.join(Source_path,'log','user1.log')
# D:/shopping_cartA8\log\user1.log
# print(LOG1_path)

src.py

from interface import user
from interface import bank
from interface import shop
from lib import common
# 设置一个用户的信息,登录的状态
user_data={'name':None,
           'is_auth':False,}

import time
def login():
    '''
    登录函数,密码输错三次锁定,用户名输错可以一直输入
    :return:
    '''
    if user_data['is_auth']:
        print('已登录')
        return
    print('请登录')
    count = 0
    while True:
        name = input('输入用户名').strip()
        # 需要查询是否用户存在
        # 开始省代码
        user_dic = user.get_userinfo_by_name(name)
        if user_dic:
            # 是否锁定
            # 锁定状态
            if user_dic['locked']:
                time.sleep(5)
                count = 0
                # 需要的解锁定 写入 user_dic  locked 变 False  写入 json数据修改
                # ???
                user.unlock_user(name)
                continue
            pwd = input('输入密码').strip()
            if user_dic['password'] == pwd and user_dic['locked'] == False:
                user_data['name'] = name
                user_data['is_auth'] = True
                common.log('登录成功')
                print('登录成功')
                break
            else:
                print('密码错误')
                count += 1
            if count>=3:
                user.lock_user(name)
        else:
            print('用户名不存在')
















def register():
    if user_data['is_auth']:
        print('已登录')
        return
    print('注册')
    while True:
        name = input('输入用户名').strip()
        # 查看用户是否已经注册需要用到接口interface  对应的  user
        user_dic=user.get_userinfo_by_name(name)
        # print(user_dic)
        if not user_dic:
            pwd = input('输入密码').strip()
            pwd1 = input('确认密码').strip()
            if pwd == pwd1:

                user.register_user(name,pwd)
                break


        else:
            print('用户名已经存在')


@common.login_intter
def check_balance():
    print('查看余额')
#     需要 interface 接口 bank.py 模块 check_balance_interface方法
#     # 传入登录名字调用接口加工字典account对应的value余额
    balance = bank.check_balance_interface(user_data['name'])
    print('你的余额为%s' % balance)
@common.login_intter
def transfer():
    print('转账')
    while True:
        trans_name = input('请输入转入用户名,q返回退出转账').strip()
        if trans_name == user_data['name'] or trans_name == user_data['name'].upper():
            print('不能给自己转账')
            continue
        if 'q' == trans_name:
            break
        # 查看转账用户是否存在
        trans_dic = user.get_userinfo_by_name(trans_name)
        if trans_dic:
            trans_money = input('输入转账金额').strip()
            # 纯数字的字符串类型
            if trans_money.isdigit():
                trans_money = int(trans_money)
                if trans_money > 0:
                    # 调用查询余额接口,根据登录名拿到余额
                    user_balance=bank.check_balance_interface(user_data['name'])
                    # 用户的余额必须大于转入的钱
                    if user_balance > trans_money:
                        # 写转账接口 user_data['name'],trans_name,trans_money
                        bank.transfer_interface(user_data['name'], trans_name, trans_money)
                        break
                else:
                    print('不能为负数')
        else:
            print('用户不存在')





@common.login_intter
def repay():
    print('存款')
    while True:

        account=input('请输入存款的金额,输入q退出').strip()
        if account == 'q': break
        if account.isdigit():
            account = int(account)
            if account > 0:

                # 调用存款接口执行存款的业务逻辑,传入用户名和存款金额
                bank.repay_interface(user_data['name'], account)
                break
            else:
                print('存款大于0')
        else:
            print('请输入数字')






@common.login_intter
def withdraw():
    print('取款')
    while True:
        qukuan_money = input('请输入取款金额').strip()
        if 'q' == qukuan_money: break
        if qukuan_money.isdigit():
            qukuan_money = int(qukuan_money)
            if qukuan_money>0:
                # 调用查询余额接口,根据登录名拿到余额
                user_account = bank.check_balance_interface(user_data['name'])
                # 取款
                if user_account >= qukuan_money:
                    # 调用取款接口执行取款的业务逻辑,传入用户名和取款金额
                    bank.withdraw_interface(user_data['name'], qukuan_money)
                    print('取款%s元成功' % qukuan_money)
                    break
                else:
                    print('钱不够')


            else:
                print('取款金额需大于0')

        else:
            print('输入数字')
@common.login_intter
def check_record():
    print('查看流水')
    # 调用查看流水接口执行查看流水的业务逻辑,传入用户名
    bankflow = bank.check_bankflow_interface(user_data['name'])
    # print(bankflow)
    for record in bankflow:
        print(record)
@common.login_intter
def shopping():
    print('购物')
    goods_list = [
        ['coffe', 30],
        ['chicken', 20],
        ['iPhone', 8000],
        ['macBook', 12000],
        ['car', 100000]
    ]
    shopping_cart = {}
    # 调用查询余额接口,根据登录名拿到余额
    user_money = bank.check_balance_interface(user_data['name'])
    cost_money = 0
    while True:
        for i, item in enumerate(goods_list):
            print(i, item)
        choice = input('请输入购物编号').strip()
        if choice.isdigit():
            choice = int(choice)
            if choice < 0 or choice >= len(goods_list): continue
            goods_name = goods_list[choice][0]
            goods_price = goods_list[choice][1]
            if user_money >= goods_price:
                if goods_name in shopping_cart:  # 原来已经购买过
                    shopping_cart[goods_name]['count'] += 1
                    shopping_cart[goods_name]['price'] = shopping_cart[goods_name]['count'] * goods_price
                else:
                    shopping_cart[goods_name] = {'price': goods_price, 'count': 1}
                user_money -= goods_price
                cost_money += goods_price
                print('%s 新的购物商品' % goods_name)
            else:
                print('钱不够')
                continue
        elif choice == 'q':
            print(shopping_cart)
            buy = input('卖不卖 (y/n)>>:').strip()
            if buy == 'y':
                # 正常需要加密码验证
                if cost_money == 0: break
                # 三十
                # 调用购物接口,传入用户数据,购物车,花费金额
                shop_success=shop.shopping_interface(user_data['name'], shopping_cart, cost_money)
                if shop_success:
                    print('购买成功')
                    break
                else:
                    print('钱不够')
                    break
            else:
                print('不买')
                break
        else:
            print('非法输入')

















@common.login_intter
def look_shoppingcart():
    print('查看购物车')
    # 调用查看购物车接口,传入用户名
    shopping_s = shop.check_shoppingcart(user_data['name'])
    print(shopping_s)


def loginout():
    user_data['is_auth'] = False
    print('注销')

fun_dic={'1':login,
         '2':register,
         '3':check_balance,
         '4':transfer,
         '5':repay,
         '6':withdraw,
         '7':check_record,
         '8':shopping,
         '9':look_shoppingcart,
         '10':loginout,
         }




def run():
    while True:
        print("""
        "1":登录
        "2":注册
        "3":查看余额
        "4":转账
        "5":存款
        "6":取款
        "7":查看流水
        "8":购物
        "9":查看购买商品
        "10":注销

            """)
        choice = input('输入操作编号').strip()
        if choice not  in fun_dic:continue
        # print(fun_dic[choice])
        fun_dic[choice]()







db_handle.py

# 六.注册的用户信息保存成序列化json文件
# 思路
# 1.路径
# 2.有json模块,存储成序列化文件
import json
import os
from conf import setting
class Serialization:
    # 反序列化方法,读的方法
    def select(self,name):
        # print(name)
        # print('select')
        # 读取一个文件信息,我们需要什么?
        # 1.需要文件路径
        # 思路
        # 我们可以通过json文件名进行查询,
        # 如果查到文件存在,说明已经注册了,
        # 不存在,代表没注册
        # 路径写道setting里面  ???
        # D:\shopping_cartA8\db/dahai.json
        # 存在
        # D:/shoping_cart_A7\db/李老师.json
        path = r'%s/%s.json'%(setting.DB_path,name)
        # print(path)
        # 有李老师.json这个json文件就返回,没有就返回False
        # 返回给谁  bank shop user 这个三个接口 都可能用的上
        if os.path.isfile(path):
            # print('文件存在')
            # print('用户存在')
            with open(path,'r',encoding='utf-8')as f:
                dic=json.load(f)
                # print(dic)
                return dic
        else:
            # print('文件不存在')
            # print('用户不存在')
            return False

    # 序列化
    def update(self,user_dic):
        path_file = os.path.join(setting.DB_path,'%s.json'%user_dic['name'])
        # D:\shopping_cartA8\db\李老师.json
        # 注册是利用json文件名注册  数据写入文件
        with open(path_file,'w',encoding='utf-8')as f:
            # ensure_ascii=False可以显示中文
            json.dump(user_dic,f,ensure_ascii=False)
            f.flush()





db_serialization=Serialization()

user.py

from db.db_handle import  db_serialization
from lib import common
def get_userinfo_by_name(name):
    '''
            写一个查询用户信息的接口
            :param name:
            :return:
    '''
    # 这里需要用到一个db 下面的 db_handle 数据管理的方法在这个文件夹下
    # 这里需要返回用户信息   ???
    return db_serialization.select(name)
    # return ????


def register_user(name,password,balance= 15000):
    '''
            注册用户接口
            :param name:
            :param password:
            :param balance:
            :return:
    '''
    # 信息传入定义的字典
    user_dic = {'name': name, 'password': password, 'locked': False, 'account': balance, 'shopping_cart': {},
                'bankflow': []}
    # 这个字典到时候会存储成json文件
    # 需要通过谁写入    ???
    # db包  db_handle模块 的 db_serialization 对象的方法
    # db_serialization
    db_serialization.update(user_dic)
    print('%s 注册了'%name)
    # 存储一个日志
    # 日志是公用的 在lib 文件夹 common 写方法 数据存储到 log 文件夹里面
    # 需要添加log 下面日志文件的路径到 setting 里面
    common.log('%s 注册了'%name)


def lock_user(name):
    '''
        锁定用户接口
        :param name:
        :return:
        '''
    # 拿到注册用户的字典信息
    user_dic = db_serialization.select(name)
    # 锁定改成True
    user_dic['locked'] = True
    # 重新写入字典信息
    db_serialization.update(user_dic)
    print('密码输入错误3次锁定5秒,请5秒后再登录')
    print('已被锁定')
    # 记录日志
    common.log('已被锁定')


def unlock_user(name):
    '''
            解锁用户接口
            :param name:
            :return:
            '''
    # 拿到注册用户的字典信息
    user_dic = db_serialization.select(name)
    # 锁定改成True
    user_dic['locked'] = False
    # 重新写入字典信息
    db_serialization.update(user_dic)
    print('已被解锁')
    # 记录日志
    common.log('已被解锁')























bank.py

from lib import common
from interface import user
from db.db_handle import  db_serialization

def check_balance_interface(name):
    '''
            查看余额接口
            :param name:
            :return:
            '''
    print('%s 查看了余额' % (name))
    common.log('%s 查看了余额' % name)
    # 思考逻辑 , 后面代码不用管了 一条龙服务
    user_dic=user.get_userinfo_by_name(name)
    return user_dic['account']

def transfer_interface(from_name, to_name, account):
    '''
            转账接口输入自己name,别人name,和钱
            :param from_name:
            :param to_name:
            :param account:
            :return:
    '''
    from_user_dic = user.get_userinfo_by_name(from_name)
    to_user_dic = user.get_userinfo_by_name(to_name)
    if from_user_dic['account'] >= account:  # 比较自己的钱和需要转入的钱
        from_user_dic['account'] -= account  # 自己的钱减
        to_user_dic['account'] += account  # 别人的钱加
        # 记录
        from_user_dic['bankflow'].extend(['%s 转账 %s 元 给 %s'%(from_name, account, to_name)])
        to_user_dic['bankflow'].extend(['%s 收到 %s 转账 %s'%(to_name, from_name, account)])
        # 写入json 更新用户转账数据
        db_serialization.update(from_user_dic)
        db_serialization.update(to_user_dic)
        common.log('%s 收到 %s 转账 %s' % (to_name, from_name, account))
        print('%s 向 %s 转账 %s' % (from_name, to_name, account))

    else:
        print('转账钱不够')


def repay_interface(name,account):
    '''
            存款接口
            :param name:
            :param account:
            :return:
            '''
    # # 查询json用户获取用户字典
    user_dic = db_serialization.select(name)
    # 用户字典余额加上存款金额
    user_dic['account'] += account
    user_dic['bankflow'].append('%s 存入 %s 元' % (name, account))
    # # 写入json 更新用户存款数据
    db_serialization.update(user_dic)
    print('%s存款了%s' % (name, account))
    common.log('%s存款了%s' % (name, account))


def withdraw_interface(name,account):
    '''
        取款接口
        :param name:
        :param account:
        :return:
        '''
    # # 查询json用户获取用户字典
    user_dic = db_serialization.select(name)
    # 用户字典余额加上取款金额
    user_dic['account'] -= account
    user_dic['bankflow'].append('%s 取出 %s 元' % (name, account))
    # # 写入json 更新用户存款数据
    db_serialization.update(user_dic)
    print('%s取出了%s' % (name, account))
    common.log('%s取出了%s' % (name, account))


def check_bankflow_interface(name):
    '''
        银行流水接口
        :param name:
        :return:
        '''
    # # 查询json用户获取用户字典
    user_dic = db_serialization.select(name)
    common.log('%s 查看银行流水' % name)
    return user_dic['bankflow']


def consum_interface(name, account):
    '''
        消费接口
        :param name:
        :param account:
        :return:
        '''
    # 查询用户json字典
    user_dic = user.get_userinfo_by_name(name)
    # 用户的钱和花费的钱进行比较
    if user_dic['account'] >= account:
        user_dic['account'] -= account
        # 添加到bankflow列表里面记录流水
        user_dic['bankflow'].extend(['%s 消费了 %s 元钱' % (name, account)])
        db_serialization.update(user_dic)
        common.log('%s 消费了 %s 元钱' % (name, account))
        print(('%s 消费 %s 元' % (name, account)))
        return  True

    else:
        return False

shop.py

from interface import bank
from interface import user
from db.db_handle import db_serialization
from lib import common
def shopping_interface(name, shopping_cart, cost_money):
    '''
            购物接口
            :param name:
            :param shopping_cart:
            :param cost_money:
            :return:
    '''
    # 需要消费进行扣款,那么这个应该和银行打交道 调用 bank 接口去做这件事情
    # 这个银行的接口要判断我的钱是否大于花费的钱
    # 是否扣款成功

    consum_success=bank.consum_interface(name,cost_money)
    if consum_success:
        # 保存购物车
        # 查询用户json字典
        user_dic =   user.get_userinfo_by_name(name)
        user_dic['shopping_cart'] = shopping_cart
        # 更新用户json字典
        db_serialization.update(user_dic)
        common.log('%s 花费 %s 购买了 %s' % (name, cost_money, shopping_cart))
        print('%s 花费 %s 购买了 %s' % (name, cost_money, shopping_cart))
        return True
    else:# 不能花费成功就不能购物成功
        return False

def check_shoppingcart(name):
    # 查询用户json字典
    user_dic = user.get_userinfo_by_name(name)
    print('%s 查看了购物车'%name)
    common.log('%s 查看了购物车' % name)
    return user_dic['shopping_cart']

common.py

from  conf import setting


import time
from core import src
# 日志写入数据方法
def log(msg):
    current_time = time.strftime('%Y-%m-%d %X')
    with open(setting.LOG1_path,'a',encoding='utf-8')as f:
        f.write(current_time+'-'*6+msg+'\n')

def login_intter(func):
    '''
        func就是它们
        '3':check_balance,
        '4':transfer,
        '5':repay,
        '6':withdraw,
        '7':check_record,
        '8':shopping,
        '9':look_shoppingcart,
        '10':loginout,
        都要在登录的情况下才能执行
        全部都写一个登录装饰器
        公用的在common里面写
        '''
    def wrapper():
        if not src.user_data['is_auth']:# 非登录就满足条件
            src.login()
        else:# 已经登录就不满足条件
            func()


    return wrapper



5.购物车总结

一.运用了框架思维,极大的提高了编程能力。

生活心得,融到课程里面

停下来(做实验)

编程打断点看数据 ,直接print

二.灵活运用的python核心语法的知识

数据类型(字符串******,列表******,字典******) 可变和不可变的理解******,数据类型会自带布尔值*****

控制流程
while循环和if的连用
for循环和if的连用
break
continue

函数(功能***,参数*****,返回值*******)

面向对象(__init__和绑定对象的方法)
以双下划线开头且以双下划线结尾的固定方法,他们会在特定的时机被触发执行,
__init__就是其中之一,它会在实例化之后自动被调用,以完成实例的初始化。
绑定对象的方法  self

模块
导入模块

posted @ 2022-10-26 15:43  adqwe  阅读(9)  评论(0编辑  收藏  举报