南宫乘风:我在学Python哦
Python:你不写Python项目,是不会有进步的,年轻人,耗子尾汁吧
南宫乘风:我要进步,要学习,开始项目
Python:来骗,来偷袭。很快啊!年轻人,不讲码德
学了一点时间Python,为了巩固基础,拿一个简单的项目练手。
ATM+购物车功能(ps:很简单,大佬不要嘲笑哈)项目需求:
1.额度15000或自定义 --> 注册功能 2.实现购物商城,买东西加入购物车,调用信用卡接口结账 --> 购物功能、支付功能 3.可以提现,手续费5% --> 提现功能 4.支持多账户登录 --> 登录功能 5.支持账户间转账 --> 转账功能 6.记录日常消费 --> 记录流水功能 7.提供还款接口 --> 还款功能 8.ATM记录操作日志 --> 记录日志功能 9.提供管理接口,包括添加账户、用户额度,冻结账户等。。。 ---> 管理员功能 10.用户认证用装饰器 --> 登录认证装饰器
"用户视图层" 展示给用户选择的功能
user 1、注册功能 2、登录功能 3、查看余额 4、提现功能 5、还款功能 6、转账功能 7、查看流水 8、购物功能 9、查看购物车 10、管理员功能
admin
1、添加账号 2、修改额度 3、冻结账号 4、解冻账号 5、返回上一层
架构流程图
采取MVC的架构方式
各层分开,编写接口
三层架构:
1、把每个功能都分层三部分,逻辑清晰 2、如果用户更换不同的用户界面或不同的数据库存储机制,不会影响接口层的核心逻辑代码,扩展性强。 3)可以在接口层,准确的记录日志与流水。
三层架构构建 项目代码:https://wwx.lanzoux.com/i1vhGixijzi
启动界面
start.py(程序的入口)
'''
程序入口
'''
import os
import sys
from core import src
# 添加解释器的环境变量
sys.path.append(
os.path.dirname(__file__)
)
# 开始执行项目main
if __name__ == "__main__":
src.run()
conf
setting.py(log日志的配置文件,项目的环境配置)
'''
配置文件设置
'''
import os
BASE=os.path.dirname(os.path.dirname(__file__))
# print(BASE)
#获取user_date文件夹路径
USER_DATE=os.path.join(BASE,'db','user_date')
# print(USER_DATE)
"""
日志配置字典LOGGING_DIC
"""
# 1、定义三种日志输出格式,日志中可能用到的格式化串如下
# %(name)s Logger的名字
# %(levelno)s 数字形式的日志级别
# %(levelname)s 文本形式的日志级别
# %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
# %(filename)s 调用日志输出函数的模块的文件名
# %(module)s 调用日志输出函数的模块名
# %(funcName)s 调用日志输出函数的函数名
# %(lineno)d 调用日志输出函数的语句所在的代码行
# %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
# %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
# %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
# %(thread)d 线程ID。可能没有
# %(threadName)s 线程名。可能没有
# %(process)d 进程ID。可能没有
# %(message)s用户输出的消息
import os
BASE_PATH=os.path.dirname(os.path.dirname(__file__))
a1_path=os.path.join(BASE_PATH,'log','a1.log')
a2_path=os.path.join(BASE_PATH,'log','a2.log')
# print(a1_path+'\n'+a2_path)
# 2、强调:其中的%(name)s为getlogger时指定的名字
standard_format = '%(asctime)s - %(threadName)s:%(thread)d - 日志名字:%(name)s - %(filename)s:%(lineno)d -' \
'%(levelname)s - %(message)s'
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
test_format = '%(asctime)s] %(message)s'
# 3、日志配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
'test': {
'format': test_format
},
},
'filters': {},
# handlers是日志的接收者,不同的handler会将日志输出到不同的位置
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件
# 'maxBytes': 1024*1024*5, # 日志大小 5M
'maxBytes': 1024*1024*5,
'backupCount': 5,
'filename': a1_path, # os.path.join(os.path.dirname(os.path.dirname(__file__)),'log','a2.log')
'encoding': 'utf-8',
'formatter': 'standard',
},
#打印到文件的日志,收集info及以上的日志
'other': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # 保存到文件
'filename': a1_path, # os.path.join(os.path.dirname(os.path.dirname(__file__)),'log','a2.log')
'encoding': 'utf-8',
'formatter': 'standard',
},
},
# loggers是日志的产生者,产生的日志会传递给handler然后控制输出
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'kkk': {
'handlers': ['console','other'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
},
'终端提示': {
'handlers': ['console',], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
},
'': {
'handlers': ['default', ], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
},
},
}
core
admin.py(admin用户视图)
from core import src
from interface import admin_interface
def add_user():
src.register()
def change_balance():
while True:
# 输入修改修改用户名
change_user = input('请输入需要修改额度的用户:').strip()
change_money = input('请输入需要修改的用户额度:').strip()
if not change_money.isdigit():
continue
if int(change_money) >= 0:
flag, msg = admin_interface.change_balance_interafce(change_user, change_money)
if flag:
print(msg)
else:
print(msg)
else:
print('输入的额度不正确')
def disable_user():
# 输入要冻结的用户
while True:
dis_user = input('请输入要冻结的用户:').strip()
flag, msg = admin_interface.disable_user_interface(dis_user)
if flag:
print(msg)
break
else:
print(msg)
def enable_user():
# 输入要解冻冻结的用户
while True:
dis_user = input('请输入要解冻冻结的用户:').strip()
flag, msg = admin_interface.enable_user_interface(dis_user)
if flag:
print(msg)
break
else:
print(msg)
def lsat_men():
from core import src
src.run()
func_dic = {
'1': add_user,
'2': change_balance,
'3': disable_user,
'4': enable_user,
'5': lsat_men,
}
def admin_run():
while True:
print('''
1、添加账号
2、修改额度
3、冻结账号
4、解冻账号
5、返回上一层
''')
choice = input('请输入管理员功能编号:').strip()
if choice not in func_dic:
print("请输入正确的功能编号")
continue
func_dic.get(choice)()
# if __name__ == '__main__':
# admin()
src.py(用户的视图)
'''
用户视图层
'''
from interface import user_interface, bank_interface, shop_interface
from lib import common
from core import admin
# 1、注册功能
'''def register():
while True:
# 1 让用户输入用户名称和密码进行校验
username = input('请输入用户:').strip()
if username.strip()=='':
print("请输入正确的用户名")
continue
user_path = os.path.join(setting.USER_DATE, f"{username}.json")
if os.path.exists(user_path):
print(f"您输入的用户名:{username}已经存在")
continue
password = input("请输入密码:").strip()
re_password = input("请确认密码:").strip()
# 判断密码是否一致
if password == re_password:
# 2 查看用户是否存在
# 3 如用户存在,则让用户重新输入
# 4 如用户不存在,则保存用户数据
# 4.1 组织用户的数据的字典信息
user_dic = {
'username': username,
'password': password,
'balance': 15000,
# 用于记录用户的流水类表
'flow': [],
# 用于记录用户购物车
'shop_car': [],
# locaked :用于记录用户是否冻结
# false:未冻结 True:已经被冻结
'locaked': False
}
# 用户数据tank.json
user_path = os.path.join(setting.USER_DATE, f"{username}.json")
with open(user_path, 'w', encoding='utf-8') as f:
json.dump(user_dic, f)
else:
print('您的两次密码不一致,请重新输入')'''
login_user = None
# 分层版
def register():
while True:
# 1 让用户输入用户名称和密码进行校验
username = input('请输入用户:').strip()
if username.strip() == '':
print("请输入正确的用户名")
continue
password = input("请输入密码:").strip()
re_password = input("请确认密码:").strip()
# 判断密码是否一致
if password == re_password:
# 2 调用接口层的注册结果。将用户名和密码传到接口层
# (True, 用户注册成功), (False, 注册失败)
flag, msg = user_interface.register_interface(
username, password
)
# 3) 根据flag判断用户注册是否成功,flag控制break的结束
if flag:
print(msg)
break
else:
print(msg)
else:
print('您的两次密码不一致,请重新输入')
# 2、登录功能
def login():
# 登录视图层
while True:
username = input('请输入用户名:').strip()
password = input('请输入用户名密码:').strip()
flag, msg = user_interface.longin_interface(username, password)
if flag:
global login_user
login_user = username
print(msg)
break
else:
print(msg)
# 3、查看余额
@common.login_auth
def check_balance():
# 直接调用查看用户接口,获取用余额
balance = user_interface.check_balance_interface(login_user)
print(f'用户:{login_user}账号余额为:{balance}')
# 4、提现功能
@common.login_auth
def withdraw():
while True:
# 让用户输入体现金额
input_money = input('请输入提现金额:').strip()
# 判断用户输入的金额是否是数字
if not input_money.isdigit():
print('请重新输入:')
continue
# 用户提现,将金额提交接口处理
flag, msg = bank_interface.withdraw_interface(login_user, int(input_money))
if flag:
print(msg)
break
else:
print(msg)
# 5、还款功能
@common.login_auth
def repay():
while True:
# 让用户输入体现金额
repay_money = input('请输入还款金额:').strip()
# 判断用户输入的金额是否是数字
if not repay_money.isdigit():
print('请重新输入')
continue
# 用户提现,将金额提交接口处理
if int(repay_money) > 0:
flag, msg = bank_interface.repay_interface(login_user, int(repay_money))
if flag:
print(msg)
break
else:
print('不能输入小于0的数字')
# 6、转账功能
@common.login_auth
def transfer():
'''
接收用户的转账金额
接收用户输入的转账目标
:return:
'''
while True:
user_money = input('请输入转账目标用户:').strip()
money = input('请输入转账金额:').strip()
if not money.isdigit():
print('请输入正确的金额!')
continue
money = int(money)
if money > 0:
# 转账接口
flag, msg = bank_interface.transfer_interface(login_user, user_money, money)
if flag:
print(msg)
break
else:
print(msg)
else:
print('请输入正确的金额!')
# 7、查看流水
@common.login_auth
def check_flow():
# 直接调用查看流水的列表
flow_list = bank_interface.check_flow_interface(login_user)
if flow_list:
for flow in flow_list:
print(flow)
else:
print('当前用户没有流水记录')
# 8、购物功能
@common.login_auth
def shopping():
'''
{
'0':{'name':'包子','price':30},
'0': {'name': '包子', 'price': 30},
'0': {'name': '包子', 'price': 30},
}
:return:
'''
shop_list = [
['包子', 30],
['衣服', 150],
['安全套', 25],
['情趣内衣', 520],
['cosplay', 250],
]
shopping_car = {}
while True:
# 先打印商品的信息,让用户选择
print('===================欢迎来到情趣商城================')
for index, shop in enumerate(shop_list):
shop_name, shop_price = shop
print(f'商品编号:{index}, 商品名称:{shop_name},商品单价:{shop_price}')
print('========================end======================')
shop_choice = input("请输入你要选购的商品编号(是否结账y or n):").strip()
if shop_choice.upper() == 'Y':
if not shopping_car:
print('购物车是空的,不能支付,请重新输入')
continue
# 调用支付接口进行支付
flag,msg=shop_interface.shopping_interface(login_user,shopping_car)
if flag:
print(msg)
break
else:
print(msg)
elif shop_choice.upper() == 'N':
# 判断当前用户是否添加过购物车
if not shopping_car:
print('购物车是空的,不能添加,请重新输入')
continue
flag,msg=shop_interface.add_shop_car_interface(login_user,shopping_car)
if flag:
print(msg)
break
if not shop_choice.isdigit():
print('请输入正确的编号!')
continue
shop_choice = int(shop_choice)
if shop_choice not in range(len(shop_list)):
print('请输入正确的编号!')
continue
shop_name, shop_price = shop_list[shop_choice]
if shop_name in shopping_car:
shopping_car[shop_name][1] += 1
else:
shopping_car[shop_name] = [shop_price, 1]
print("当前购物车:",shopping_car)
# 9、查看购物车
@common.login_auth
def check_shop_car():
shop_list = shop_interface.check_shop_car_interface(login_user)
if shop_list:
for shop_name,print_number in shop_list.items():
print(f'商品:[{shop_name}],数量:[{print_number[1]}]')
else:
print('当前用户没有流水记录')
@common.login_auth
def admin_spuer():
admin.admin_run()
# 创建函数功能字典
func_dic = {
'1': register,
'2': login,
'3': check_balance,
'4': withdraw,
'5': repay,
'6': transfer,
'7': check_flow,
'8': shopping,
'9': check_shop_car,
'10': admin_spuer,
}
def run():
while True:
print('''
==========ATM+购物车==========
1、注册功能
2、登录功能
3、查看余额
4、提现功能
5、还款功能
6、转账功能
7、查看流水
8、购物功能
9、查看购物车
10、管理员功能
========== end ==========
''')
choice = input("请输入功能编号:").strip()
if choice not in func_dic:
print("请输入正确的功能编号")
continue
func_dic.get(choice)()
db
user_date (用户存放json的目录)
q.json (用户数据的存放文件,字典形式)
{"username": "q", "password": "099b3b060154898840f0ebdfb46ec78f", "balance": 14375.0, "flow": ["用户[q] 提现金额 [500],手续费为:[25.0]", "用户:[q]给用户[w] 转账:[100] 元 成功"], "shop_car": {}, "locked": false}
json格式
{
"username": "q",
"password": "099b3b060154898840f0ebdfb46ec78f",
"balance": 14375.0,
"flow": ["用户[q] 提现金额 [500],手续费为:[25.0]", "用户:[q]给用户[w] 转账:[100] 元 成功"],
"shop_car": {},
"locked": false
}
db_hander.py(对数据处理,相当于mysql接口处理)
'''
数据处理层
专门用户处理数据的
'''
import json
import os
from conf import setting
# 判断用户是否已经注册
def user_select(username):
# 1) 接收接口层传过来的username用户名,拼接用户json文件路径
user_path = os.path.join(
setting.USER_DATE, f'{username}.json'
)
# 2)校验用户json文件是否存在
if os.path.exists(user_path):
# 3) 打开数据,并返回给接口层
with open(user_path, 'r', encoding='utf-8') as f:
user_dic = json.load(f)
return user_dic
# 3) 不return,默认return None
# 保存数据处理
def user_save(user_dic):
user_path = os.path.join(setting.USER_DATE, f"{user_dic['username']}.json")
with open(user_path, 'w', encoding='utf-8') as f:
json.dump(user_dic, f, ensure_ascii=False)
interface
admin_interface.py(admin的业务接口处理)
from db import db_hander
from lib import common
user_logger=common.get_log('admin')
# 修改额度接口
def change_balance_interafce(change_user, change_money):
user_dic = db_hander.user_select(change_user)
if user_dic:
user_dic['balance'] = int(change_money)
db_hander.user_save(user_dic)
msg=f'[{change_user}]的额度修改{change_money}成功'
user_logger.info(msg)
return True, msg
return False, '修改额度用户不存在'
def disable_user_interface(dis_user):
user_dic = db_hander.user_select(dis_user)
if user_dic:
user_dic['locked'] = True
db_hander.user_save(user_dic)
msg = f'[{dis_user}]的冻结成功'
user_logger.info(msg)
return True, msg
else:
return False, '冻结用户不存在'
# 解冻用户的接口
def enable_user_interface(dis_user):
user_dic = db_hander.user_select(dis_user)
if user_dic:
if user_dic['locked']:
user_dic['locked'] = False
db_hander.user_save(user_dic)
msg = f'[{dis_user}]的冻结成功'
user_logger.info(msg)
return True, msg
return False,f'用户:{dis_user}处于正常状态'
else:
return False, '冻结用户不存在'
bank_interface.py(银行业务处理接口)
'''
银行相关的业务
'''
from db import db_hander
from lib import common
user_logger=common.get_log('bank')
# 用户的提现金额接口
def withdraw_interface(login_user, input_money):
# 先获取用户字典
user_dic = db_hander.user_select(login_user)
# 获取银行的金额
balance = int(user_dic.get('balance'))
# 本金+ 手续费
money = int(input_money) * 1.05
repair = round(money - input_money, 2)
# 判断用户金额是否足够
if balance >= money:
# 修改用户字典的金额
balance -= money
user_dic['balance'] = balance
flow = f'用户[{login_user}] 提现金额 [{input_money}],手续费为:[{repair}]'
user_dic['flow'].append(flow)
# 在保存数据
db_hander.user_save(user_dic)
msg=f'用户[{login_user}] 提现金额 [{input_money}],手续费为:[{repair}]'
user_logger.info(msg)
return True, msg
return False, '提现金额不足,请重新输入'
# 还款接口
def repay_interface(login_user, repay_money):
# 先获取用户字典
user_dic = db_hander.user_select(login_user)
# 获取银行的金额
balance = int(user_dic.get('balance'))
# 本金+ 手续费
money = int(repay_money)
# repair = round(money - repay_money, 2)
# 修改用户字典的金额
balance += money
user_dic['balance'] = balance
# 在保存数据
flow = f'用户:[{login_user}] 还款金额 :[{repay_money}]成功]'
user_dic['flow'].append(flow)
db_hander.user_save(user_dic)
msg = f'用户:[{login_user}] 还款金额 :[{repay_money}]成功]'
user_logger.info(msg)
return True, msg
# 转账接口
def transfer_interface(login_user, user_money, money):
# 先获取用户字典
login_user_dic = db_hander.user_select(login_user)
user_money_dic = db_hander.user_select(user_money)
# 判断目标用户是否存在
if not user_money_dic:
return False, '目标用户不存在'
if login_user == user_money:
return False, '不能给自己转账'
if login_user_dic['balance'] >= money:
login_user_dic['balance'] -= money
user_money_dic['balance'] += money
flow1 = f'用户:[{login_user}]给用户[{user_money}] 转账:[{money}] 元 成功'
login_user_dic['flow'].append(flow1)
flow2 = f'用户:[{user_money}]接受用户[{login_user}] 转账:[{money}] 元 成功'
user_money_dic['flow'].append(flow2)
db_hander.user_save(login_user_dic)
db_hander.user_save(user_money_dic)
msg = f'用户:[{login_user}]给用户[{user_money}] 转账:[{money}] 元 成功'
user_logger.info(msg)
return True, msg
msg = f'用户:[{login_user}]银行余额不足'
user_logger.info(msg)
return False, msg
# 流水接口列表查询
def check_flow_interface(login_user):
# 先获取用户字典
login_user_dic = db_hander.user_select(login_user)
flow_list = login_user_dic['flow']
return flow_list
# 支付接口
def pay_interface(login_user, cost):
user_dic = db_hander.user_select(login_user)
if user_dic.get('balance') >= cost:
user_dic['balance'] -= cost
flow = f'用户:{login_user}消费金额:{cost}'
user_dic['flow'].append(flow)
db_hander.user_save(user_dic)
user_logger.info(flow)
return True
return False
shop_interface.py(购物业务接口处理)
'''
购物商城接口
'''
from interface import bank_interface
from db import db_hander
from lib import common
shop_logger = common.get_log(log_type='shop')
# 商品准备结算接口
def shopping_interface(login_user, shopping_car):
# 计算商品总价
cost = 0
for shop_price in shopping_car.values():
price, number = shop_price
cost += (price * number)
# 逻辑校验成功,调用银行的支付接口
flag = bank_interface.pay_interface(login_user, cost)
if flag:
msg = f'用户:[{login_user}]支付 [{cost}$] 成功, 准备发货!'
shop_logger.info(msg)
return True, msg
return False, '支付失败,金额不足'
# 商品添加购物车功能
def add_shop_car_interface(login_user, shopping_car):
# 获取当前用户的购物车
user_dic = db_hander.user_select(login_user)
#原来用户的字典的商城列表
shop_car = user_dic.get('shop_car')
for shop_name, price_number in shopping_car.items():
number = price_number[1]
if shop_name in shop_car:
user_dic['shop_car'][shop_name][1] += number
else:
user_dic['shop_car'].update(
{shop_name: price_number}
)
db_hander.user_save(user_dic)
return True, '添加购物车成功'
# 查看购物车接口
def check_shop_car_interface(login_user):
# 获取当前用户的购物车
user_dic = db_hander.user_select(login_user)
shop_list = user_dic['shop_car']
return shop_list
user_interface.py(用户业务接口处理)
'''
用户相关的接口
'''
import os
import json
from db import db_hander
from lib import common
user_logger=common.get_log('user')
# 用户注册
def register_interface(username, password, balance=15000):
# 2)查看用户是否存在
# 2.1) 调用 数据处理层 中的 select函数,会返回 用户字典 或 None
user_dic = db_hander.user_select(username)
# {user: user, pwd: pwd...} or None
# 若用户存在,则return,告诉用户重新输入
if user_dic:
# return (False, '用户名已存在!')
return False, '用户名已存在!'
# 3)若用户不存在,则保存用户数据
# 做密码加密
password = common.salt(username, password)
# 3.1) 组织用户的数据的字典信息
user_dic = {
'username': username,
'password': password,
'balance': balance,
# 用于记录用户流水的列表
'flow': [],
# 用于记录用户购物车
'shop_car': {},
# locked:用于记录用户是否被冻结
# False: 未冻结 True: 已被冻结
'locked': False
}
# 3.2)保存数据
db_hander.user_save(user_dic)
msg=f'{username} 注册成功!'
user_logger.info(msg)
return True, msg
# 登录接口
def longin_interface(username, password):
# 先查看用户是否存在
user_dic = db_hander.user_select(username)
password_md5 = common.salt(username, password)
if user_dic:
print(user_dic.get('locked'))
if user_dic.get('locked'):
return False, f'用户:[{username}]已经被冻结'
if password_md5 == user_dic['password']:
msg=f'用户:[{username}] 登录成功 '
user_logger.info(msg)
return True,msg
else:
msg = f'用户:[{username}]密码错误'
user_logger.warning(msg)
return False, msg
msg = f'用户[{username}]不存在,请重新输入'
user_logger.info(msg)
return False, msg
# 查看用户余额接口
def check_balance_interface(login_user):
user_dic = db_hander.user_select(login_user)
return user_dic.get('balance')
lib
common.py(公用类,盐MD5加密,登录装饰器)
import hashlib
from core import src
from conf import setting
import logging.config
# 盐加密,通名字加密 密码
def salt(username, password):
password_ms5= hashlib.md5()
password_ms5.update((username+password).encode('utf-8'))
res = password_ms5.hexdigest()
return res
# 登录认证装饰器
def login_auth(func):
def inner(*args, **kwargs):
if src.login_user:
res = func(*args, **kwargs)
return res
else:
print('未出示证明,无法享受服务')
src.login()
return inner
# 添加日志功能(日志功能在接口层使用)
def get_log(log_type):
'''
:param log_type: user日志 bank日志 购物商城日志
:return:
'''
# 1、加载日志配置信息
logging.config.dictConfig(
setting.LOGGING_DIC
)
# 获取日志对象
logger = logging.getLogger(log_type)
return logger
log(日志文件记录)
a1.log
2020-11-29 23:03:52,782 - MainThread:13396 - 日志名字:user - user_interface.py:58 -INFO - 用户:[q]登录成功!
2020-11-29 23:04:11,089 - MainThread:13396 - 日志名字:user - user_interface.py:58 -INFO - 用户:[w]登录成功!
2020-11-29 23:04:15,584 - MainThread:13396 - 日志名字:user - user_interface.py:69 -INFO - 用户不存在,请重新输入
整体项目架构不错,可以很清楚了解到三层架构的构建
用户点击:用户视图层————————》业务接口处理————————》数据库数据处理
数据返回用户:数据处理完数据————————》业务接口处理————————》用户视图层