day012 用python实现信息卡管理及购物商城的项目
需求
#需求:
1 这是一个信用卡管理程序
2 用户手持信用卡购物,使用函数,按照软件开发规范
3 用户名密码存放于文件中,支持多用户登陆,使用json
4 程序启动,先登录或者注册,保存信息到文件中,记录日志
5 用户的登陆,密码输错三次,锁定,不能再登录
6 用户可以取现,消费,还款,提额
7 允许用户根据商品编号购买商品,用户选择商品,检测余额,够用扣款,不够用提示,用户行为都要记录日志
8 用户可以随时退出,退出时,打印已购买商品和余额
借鉴了老师在day011中的代码框架,添加了部分代码。
项目的结构如下。
项目的目录结构如下。
项目的运行结果展示
待改进的地方
1. 未做到单点登录
2. 日志的信息不够详细
3. 项目的健壮性,输入校验等等,有待提高
代码如下。
#/bin/start.py
import sys,os
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.append(BASE_DIR)
from core import src
if __name__ == '__main__':
src.run()
#/conf/setting.py
import os
BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DB_PATH=os.path.join(BASE_DIR,'db','db.json')
LOG_PATH=os.path.join(BASE_DIR,'log','access.log')
LOGIN_TIMEOUT=3
"""
logging配置
"""
# 定义三种日志输出格式
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
# log配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
},
'filters': {},
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
#打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
'formatter': 'standard',
'filename': LOG_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)传递
},
},
}
#/core/src.py
from conf import settings
from lib import common
import time
logger=common.get_logger(__name__)
current_user={'user':None,'login_time':None,'timeout':int(settings.LOGIN_TIMEOUT)}
def auth(func):
def wrapper(*args,**kwargs):
if current_user['user']:
interval=time.time()-current_user['login_time']
if interval < current_user['timeout']:
return func(*args,**kwargs)
name = input('name>>: ')
db=common.conn_db()
if db.get(name): #已注册用户的登录流程
if db.get(name).get('locked'):
logger.warning('该用户已被锁定')
print ('该用户已被锁定')
else:
logging_error_times = 0
while True:
if logging_error_times >= 3:
logger.warning('密码输入错误3次,该用户已被')
db[name]['locked'] = 1
common.save_db(db)
break
password = input('password>>:')
if password == db.get(name).get('password'):
logger.info('登录成功')
print('登录成功')
current_user['user'] = name
current_user['login_time'] = time.time()
return func(*args, **kwargs)
else:
logger.warning('密码错误')
logging_error_times += 1
else: #注册
is_register = input('是否注册? (Y/N)')
if is_register in ['Y','y']:
password = input('password>>')
db[name] = {"password":password, "money":0, "locked":0}
logger.info("登录成功")
print('登录成功')
current_user['user'] = name
current_user['login_time'] = time.time()
common.save_db(db)
return func(*args, **kwargs)
else:
logger.info('用户不注册')
return wrapper
@auth
def buy():
db = common.conn_db()
money = db.get(current_user['user']).get('money')
print ('目前账户有%d元' %money)
items_dict = {'item1':1, 'item2':2}
print (items_dict.keys())
items_bought_dic = {}
while True:
item_buy = input('buy which(Q退出)?>>').strip()
item_buy_split = item_buy.split(' ')
#print (item_buy_split[0], item_buy_split[1])
if item_buy_split[0] in ['q', 'Q']:
db[current_user['user']]['money'] = money
common.save_db(db)
print('你买了:',items_bought_dic)
print('账户余额:',money)
break
elif item_buy_split[0] in items_dict:
item, item_num = item_buy_split[0], item_buy_split[1]
item_price = items_dict[item] * int(item_num)
print(item,':',item_num,'共花了%d'%item_price)
if item_price <= money:
money -= item_price
print ('购买成功,还有%d元'%money)
if item in items_bought_dic:
items_bought_dic[item] += item_num
else:
items_bought_dic[item] = item_num
else:
print ('余额不足')
else:
print ('请输入:【商量名称】 【商品数量】')
@auth
def withdraw():
db = common.conn_db()
money = db.get(current_user['user']).get('money')
print ('账户余额%d元' %money)
withdraw_num = int(input('取多少钱?'))
if withdraw_num <= money:
money -= withdraw_num
db[current_user['user']]['money'] = money
common.save_db(db)
print ('取现成功,账户余额%d' % money)
else:
print ('账户余额不足')
@auth
def repay():
db = common.conn_db()
money = db.get(current_user['user']).get('money')
print('账户余额%d元' % money)
repay_num = int(input('还款数量? '))
money += repay_num
db[current_user['user']]['money'] = money
common.save_db(db)
print('还款成功,你还有%d' % (money))
@auth
def run():
print('''
1. 取现
2. 还款
3. 消费
Q. 退出
''')
while True:
choice = input('>>: ').strip()
if not choice:continue
if choice == '1':
withdraw()
if choice == '2':
repay()
if choice == '3':
buy()
if choice in ['Q','q']:
quit()
#/db/db.json
{"user1": {"password": "111", "money": 2705, "locked": 0}, "user2": {"password": "111", "money": 30000, "locked": 0}, "user3": {"password": "111", "money": 20000, "locked": 0}, "zjl": {"password": "111", "money": 0, "locked": 0}}
#/lib/common.py
from conf import settings
import logging
import logging.config
import json
def get_logger(name):
logging.config.dictConfig(settings.LOGGING_DIC) # 导入上面定义的logging配置
logger = logging.getLogger(name) # 生成一个log实例
return logger
def conn_db():
db_path=settings.DB_PATH
dic=json.load(open(db_path,'r',encoding='utf-8'))
return dic
def save_db(dic):
db_path = settings.DB_PATH
json.dump(dic, open(db_path, 'w', encoding='utf-8'))
日志的截图