700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 〖Python 数据库开发实战 - Python与Redis交互篇⑫〗- 综合案例 - 新闻管理系统

〖Python 数据库开发实战 - Python与Redis交互篇⑫〗- 综合案例 - 新闻管理系统

时间:2020-08-14 10:19:24

相关推荐

〖Python 数据库开发实战 - Python与Redis交互篇⑫〗- 综合案例 - 新闻管理系统

前言

✌ 作者简介:渴望力量的哈士奇 ✌,大家可以叫我 🐶哈士奇🐶 ,一位致力于 TFS - 全栈 赋能的博主 ✌

🏆 CSDN博客专家认证、新星计划第三季全栈赛道 MVP 、华为云享专家、阿里云专家博主 🏆

📫 如果文章知识点有错误的地方,请指正!和大家一起学习,一起进步👀

💬 人生格言:优于别人,并不高贵,真正的高贵应该是优于过去的自己。💬

🔥 如果感觉博主的文章还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主哦

文章目录

❣️ 实现新闻删除功能 - "redis_new_dao.py" - 删除 redis 缓存中的新闻记录 - delete_cache() 方法❣️ 实现新闻删除功能 - "news_service.py" - 删除 redis 缓存中的新闻记录 - delete_cache()❣️ 实现新闻删除、删除缓存功能 - "app.py" - 修改 "删除新闻" - 删除缓存数据

接下来我们继续来完成《新闻管理系统》 的开发,上一章节我们是将 “审批通过” 的新闻 缓存到了 “redis” 里面。这一章节我们就来实现一下,当 “管理员” 执行 “删除新闻” 的时候,MySQL 与 Redis 里面的记录都删除的功能吧。

PS:这里执行删除动作的角色,是管理员的权限,“新闻编辑” 角色的用户是没有 “删除新闻” 的权限的!

❣️ 实现新闻删除功能 - “redis_new_dao.py” - 删除 redis 缓存中的新闻记录 - delete_cache() 方法

“redis_news_dao.py” 模块封装的是缓存的 redis 的数据,insert() 函数是像 redis 中添加数据;这次我们要实现的是删除掉缓存中的数据,所以我们需要定义一个新的函数 -delete();代码示例如下:重点新增了 "删除缓存记录 " -第 48 行 - 第 65 行

# coding:utf-8import redis # 导入 redis 模块from db.redis_db import redis_Pool# 导入 redis 连接池"""定义 RedisNewsDao 类"""class RedisNewsDao:"""新增缓存记录1、创建 insert() 方法,向 redis 中缓存 "审批通过" 的新闻的参数2、传入参数 id [新闻id], title [新闻标题], username [新闻作者], type [新闻类型], content [新闻内容], is_top [是否置顶], create_time [创建时间]3、针对 insert() 方法,进行异常捕获。"""def insert(self, id, title, username, type, content, is_top, create_time):"""构建连接"""con=redis.Redis(connection_pool=redis_Pool)"""异常的捕获"""try:con.hmset(id, {"title": title,"author": username,"type": type,"content": content,"is_top": is_top,"create_time": create_time})"""设置新闻置顶时间1、如果 is_top 的值为 0 ,则该新闻只置顶 24 小时2、非 0 状态的情况下,则一直置顶"""if is_top==0:con.expire(id, 24*60*60)except Exception as e:# 打印输出异常print(e)finally:# 回收连接del con"""删除缓存记录1、创建 delete_cache() 方法,传入参数 id [新闻id];根绝传入的 id 获取新闻的 key ,有则删除。2、针对 delete_cache() 方法,进行异常捕获。"""def delete_cache(self, id):"""构建连接"""con=redis.Redis(connection_pool=redis_Pool)"""异常的捕获"""try:con.delete(id)except Exception as e:# 打印输出异常print(e)finally:# 回收连接del con

❣️ 实现新闻删除功能 - “news_service.py” - 删除 redis 缓存中的新闻记录 - delete_cache()

封装 “news_service.py” ,代码内容如下:重点新增了 “删除 redis 缓存中的新闻记录” -第 87 行 - 第 93 行

# coding:utf-8from db.news_dao import NewsDaofrom db.redis_news_dao import RedisNewsDao"""定义 NewsService 类"""class NewsService:__new_dao = NewsDao()# 实例化 NewsDao ,赋值给私有变量 __new_dao__redis_news_dao = RedisNewsDao() # 实例化 RedisNewsDao ,赋值给私有变量 __redis_news_dao"""1、查询待审批新闻列表;定义 search_unreview_list 方法,传入参数 page2、调用 __new_dao 实例 的 search_unreview_list 方法,赋值给 "result",并返回结果"""def search_unreview_list(self, page):result = self.__new_dao.search_unreview_list(page)return result"""1、查询 "待审批新闻" 的总页数;定义 search_unreview_count_page 方法,不需要传入参数2、调用 __new_dao 实例 的 search_unreview_count_page 方法,赋值给 "count_page",并返回结果"""def search_unreview_count_page(self):count_page = self.__new_dao.search_unreview_count_page()return count_page"""1、审批新闻;定义 update_unreview_news() 方法,传入参数 id。2、调用 __new_dao 实例 的 update_unreview_news() 方法"""def update_unreview_news(self, id):self.__new_dao.update_unreview_news(id)"""1、查询新闻列表;定义 search_list() 方法,传入参数 apge2、调用 __new_dao 实例 的 update_unreview_news() 方法"""def search_list(self, page):result = self.__new_dao.search_list(page)return result"""查询新闻总页数"""def search_count_page(self):count_page = self.__new_dao.search_count_page()return count_page"""删除新闻1、定义 delete_by_id() 方法,传入参数 id ,2、调用 __new_dao 实例的 delete_by_id() 方法"""def delete_by_id(self, id):self.__new_dao.delete_by_id(id)"""添加新闻1、定义 insert() 方法,传入 title, editor_id, type_id, content_id, is_top2、调用 __new_dao 实例的 insert() 方法"""def insert(self, title, editor_id, type_id, content_id, is_top):self.__new_dao.insert(title, editor_id, type_id, content_id, is_top)"""查找用于缓存的新闻记录1、定义 search_cache() 方法,传入 id,通过 id 查找新闻2、调用 __new_dao 实例的 search_cache() 方法3、返回新闻记录"""def search_cache(self, id):result = self.__new_dao.search_cache(id)return result"""将需要缓存的新闻保存至redis1、定义 cache_news() 方法,并传入需要缓存的新闻的数据,传入 id, titile, username, type, content, is_top, create_time2、调用 __redis_news_dao 实例的 insert() 方法"""def cache_news(self, id, titile, username, type, content, is_top, create_time):self.__redis_news_dao.insert(id, titile, username, type, content, is_top, create_time)"""删除 redis 缓存中的新闻记录1、定义 delete_cache() 方法,并传入需要缓存的新闻的数据,传入 id2、调用 __redis_news_dao 实例的 delete_cache() 方法"""def delete_cache(self, id):self.__redis_news_dao.delete_cache(id)

❣️ 实现新闻删除、删除缓存功能 - “app.py” - 修改 “删除新闻” - 删除缓存数据

找到 “app.py” 这个模块的调用__news_service.delete_by_id(news_id)的位置,也就是第 217 行。这里是调用的__new_servicedelete_by_id()函数,通过传入的news_id删除 MySQL 中存在的新闻记录。但是只删除 MySQL 的新闻记录是没有用的,还需要将 redis 中缓存的记录删除。(毕竟只删除 MySQL 库,最后却又在 redis 查到缓存记录,影响多不好啊。)所以,在第 217 行之后,我们还需要调用__new_servicedelete_cache()函数,也就是第 218 行

# coding:utf-8from colorama import Fore, Stylefrom getpass import getpass# 该模块的作用是遮挡输入的密码from service.user_service import UserServicefrom service.news_service import NewsServicefrom service.role_service import RoleServicefrom service.type_service import TypeServiceimport os # os 模块的作用是利用 "clear" 系统命令(win电脑 - "cls"),清空控制台的内容import sys # sys 模块的作用主要是利用 "exit()" 方法进行安全退出;(释放数据库连接、文件连接...之后退出)import time__user_service = UserService()# 实例化 UserService() 对象,赋值给私有变量 "__user_service"__news_service = NewsService()__role_service = RoleService()__type_service = TypeService()while 1:os.system("clear")# 清空控制台print(Fore.LIGHTBLUE_EX, "\n\t=========================") # "\n":换行 ;"\t":table,四个空格。print(Fore.LIGHTBLUE_EX, "\n\t欢迎使用新闻管理系统")print(Fore.LIGHTBLUE_EX, "\n\t=========================")print(Fore.LIGHTGREEN_EX, "\n\t1.登录系统")print(Fore.LIGHTGREEN_EX, "\n\t2.退出系统")print(Style.RESET_ALL) # 重置字体的颜色# opt = input("\n\t请输入操作编号:") # 将用户输入的内容 赋值给变量 optopt=input("\n\t输入操作编号:")"""对用户输入的交互内容进行校验1、输入 "1" ,进入 "登录系统"2、输入 "2" ,则退出系统"""if opt=="1": # 当用户输入 1,进行 登录系统username = input("\n\t用户名:")password = getpass("\n\t密码:") # 使用 getpass() 可以将输入的密码 隐去result = __user_service.login(username, password) # 调用 __user_service 的 login 方法,实现登录;赋值给 result"""针对登录成功用户进行身份校验1、为 True ,判断 登录用户 的身份,根据对应的身份,进入对应的身份层级的轮询2、为 False ,则 登录失败,返回 登录 层级的轮询"""if result == True:role = __user_service.search_user_role(username) # 调用 __user_service 的 search_user_role 方法,校验用户身份os.system("clear")"""判断登陆成功后的身份;"新闻编辑" 与 "管理员" 分别跳转各自对应的菜单层级 """while 1:os.system("clear") # 清空终端信息if role == "新闻编辑":print(Fore.LIGHTGREEN_EX, "\n\t1.发表新闻")print(Fore.LIGHTGREEN_EX, "\n\t2.编辑新闻")print(Fore.LIGHTRED_EX, "\n\tback.退出登录")print(Fore.LIGHTRED_EX, "\n\texit.退出系统 ")print(Style.RESET_ALL)opt = input("\n\t请输入操作编号:")"""[发表新闻] 需求的实现"""if opt=="1":os.system("clear")title=input("\n\t新闻标题:") # 定义新闻标题userid=__user_service.search_userid(username)# 查询用户 idresult=__type_service.search_list()# 获得所有新闻类型"""利用 for 循环获取所有的新闻类型"""for index in range(len(result)):one = result[index]print(Fore.LIGHTBLUE_EX, "\n\t%d.%s" % (index + 1, one[1]))print(Style.RESET_ALL)opt = input("\n\t类型编号:")type_id = result[int(opt) - 1][0]#TODO 新闻正文内容;正文牵扯到 MongoDB 数据库,这里先备注个 TODO,也顺便先将 content_id 的值固定为 100content_id=100is_top=input("\n\t置顶级别(0-5):")# 设置置顶级别is_commite=input("\n\t是否提交(Y/N):")# 询问是否保存if is_commite=="Y" or is_commite=="y":# 判断用户的输入__news_service.insert(title, userid, type_id, content_id, is_top)# 传入参数print("\n\t保存成功(3秒自动返回)")time.sleep(3)elif role == "管理员":print(Fore.LIGHTGREEN_EX, "\n\t1.新闻管理")print(Fore.LIGHTGREEN_EX, "\n\t2.用户管理")print(Fore.LIGHTRED_EX, "\n\tback.退出登录")print(Fore.LIGHTRED_EX, "\n\texit.退出系统 ")print(Style.RESET_ALL)opt = input("\n\t请输入操作编号:")"""根据登录用户键入的选项,执行对应的操作"""if opt == "1":"""选项 1 :进入 "新闻管理" 三级菜单(轮询)"""while 1:os.system("clear") # 清空终端信息print(Fore.LIGHTGREEN_EX, "\n\t1.审批新闻") #print(Fore.LIGHTGREEN_EX, "\n\t2.删除新闻")print(Fore.LIGHTRED_EX, "\n\tback.返回上一层")print(Style.RESET_ALL)opt = input("\n\t输入操作编号:")# 根据输入的选项,执行对应的操作if opt=="1":"""选项 1 :进入 "审批新闻" 四级菜单(轮询)"""page=1# 定义 page 变量,保存当前是 "第1页"# page 这个变量不能定义在 while 循环内,定义在 while 内,每一次轮询都会重置 pagewhile 1:os.system("clear") # 清空终端"""1、需要导入 service包 news_service模块 NewsService类,将其赋值给 私有变量 ---> __news_service 2、__news_service 私有变量 参考 第 14 行代码"""count_page=__news_service.search_unreview_count_page() # 调用查询"待审批新闻"总页数的方法result=__news_service.search_unreview_list(page) # 将第1页的结果集赋值给 result"""将结果集通过索引的形式进行一个 for 循环输出"""for index in range(len(result)):one=result[index]print(Fore.LIGHTBLUE_EX, "\n\t%d\t%s\t%s\t%s" %(index+1, one[1], one[2], one[3]))print(Fore.LIGHTBLUE_EX, "\n\t-------------------")print(Fore.LIGHTBLUE_EX, "\n\t%d/%d" %(page, count_page))print(Fore.LIGHTBLUE_EX, "\n\t-------------------")print(Fore.LIGHTRED_EX, "\n\tback.返回上一层")print(Fore.LIGHTRED_EX, "\n\tprev.上一页")print(Fore.LIGHTRED_EX, "\n\tnext.下一页")print(Style.RESET_ALL)opt = input("\n\t输入操作编号:")"""针对用户的输入进行 判断;"""if opt=="back":# 返回上一层breakelif opt=="prev" and page>1: # 向 "上一页" 翻页,前置条件不能为 "第一页"page-=1elif opt=="next" and page<count_page: # 向 "下一页" 翻页,前置条件不能为 "最后一页"page+=1elif int(opt) >= 1 and int(opt) <= 10:""" 1、这里的 opt 获取到输入的编号是 string 类型,需要先转成 int 类型2、因为每一页的新闻数量是十条,所以输入的取值范围是 大于等于1、小于等于103、在获取输入的记录时,这里获取的新闻的id并不是数据库中新闻记录的主键id4、传入的记录其实是显示在终端的待审批新闻的索引,所以我们需要将传入的记录换算为 "待审批新闻" 的索引位"""news_id = result[int(opt) - 1][0]__news_service.update_unreview_news(news_id)result=__news_service.search_cache(news_id)# 先获取将要 "被缓存的新闻" 的结果"""将新闻的数据,按照顺序依次取出。"""title=result[0] # 新闻标题username=result[1]# 新闻作者type=result[2] # 新闻类型# TODO 查找新闻正文"""MySQL获取的 content_id ,通过 content_id 在MongoDB查找新闻正文,后续完善~"""content_id=result[3]content='100'# 当前填充数据,随意给一个 100 演示的值即可is_top=result[4] # 是否置顶create_time=str(result[5]) # 创建时间;直接获取的是 '时间类型' ,存储到 redis 中,需要变更数据类型"""调用 __news_service 封装好的 cache_news() 函数"""__news_service.cache_news(news_id, title, username, type, content, is_top, create_time)elif opt=="2":"""选项 2 :进入 "删除新闻" 四级菜单(轮询)"""page = 1 # 定义 page 变量,保存当前是 "第1页"# page 这个变量不能定义在 while 循环内,定义在 while 内,每一次轮询都会重置 pagewhile 1:os.system("clear") # 清空终端"""1、需要导入 service包 news_service模块 NewsService类,将其赋值给 私有变量 ---> __news_service 2、__news_service 私有变量 参考 第 14 行代码"""count_page = __news_service.search_count_page() # 调用 "新闻总页数" 的方法result = __news_service.search_list(page) # 将查询 "新闻列表" 的结果集赋值给 result"""将结果集通过索引的形式进行一个 for 循环输出"""for index in range(len(result)):one = result[index]print(Fore.LIGHTBLUE_EX,"\n\t%d\t%s\t%s\t%s" % (index + 1, one[1], one[2], one[3]))print(Fore.LIGHTBLUE_EX, "\n\t-------------------")print(Fore.LIGHTBLUE_EX, "\n\t%d/%d" % (page, count_page))print(Fore.LIGHTBLUE_EX, "\n\t-------------------")print(Fore.LIGHTRED_EX, "\n\tback.返回上一层")print(Fore.LIGHTRED_EX, "\n\tprev.上一页")print(Fore.LIGHTRED_EX, "\n\tnext.下一页")print(Style.RESET_ALL)opt = input("\n\t输入操作编号:")"""针对用户的输入进行 判断;"""if opt == "back": # 返回上一层breakelif opt == "prev" and page > 1: # 向 "上一页" 翻页,前置条件不能为 "第一页"page -= 1elif opt == "next" and page < count_page: # 向 "下一页" 翻页,前置条件不能为 "最后一页"page += 1elif int(opt) >= 1 and int(opt) <= 10:""" 1、这里的 opt 获取到输入的编号是 string 类型,需要先转成 int 类型2、因为每一页的新闻数量是十条,所以输入的取值范围是 大于等于1、小于等于103、在获取输入的记录时,这里获取的新闻的id并不是数据库中新闻记录的主键id4、传入的记录其实是显示在终端的新闻记录的索引,所以我们需要将传入的记录换算为 "新闻记录" 的索引位"""news_id = result[int(opt)-1][0]__news_service.delete_by_id(news_id) # 删除 MySQL 的新闻记录__news_service.delete_cache(news_id) # 删除 redis 的缓存新闻记录elif opt == "back":breakelif opt == "2":"""选项 2 :进入 "用户管理" 三级菜单(轮询)"""while True:os.system("clear")print(Fore.LIGHTGREEN_EX, "\n\t1.添加用户")print(Fore.LIGHTGREEN_EX, "\n\t2.修改用户")print(Fore.LIGHTGREEN_EX, "\n\t3.删除用户")print(Fore.LIGHTRED_EX, "\n\tback.返回上一层")print(Style.RESET_ALL)opt = input("\n\t输入操作编号:")if opt=="back":breakelif opt=="1":"""选项 1 :进入 "添加用户" 四级菜单(轮询)"""os.system("clear")username=input("\n\t用户名:")password = getpass("\n\t密码:") # getpass() 遮挡输入的密码repassword=getpass("\n\t重复密码:")# 密码需要输入两次,且需要针对两次密码进行相等判断if password!=repassword: # 两次密码不一致,进入下一次的轮询print("\n\t两次密码不一致(3秒自动返回)")time.sleep(3)continueemail=input("\n\t邮箱:")result=__role_service.search_list()# 向控制台输出已有的角色列表# 此处需要导入 service包 role_service模块 的 RoleService类# 参考 第 8 行 与 第 16 行 代码for index in range(len(result)): # 循环输出 "角色列表" 的结果集one=result[index]print(Fore.LIGHTBLUE_EX, "\n\t%d.%s" %(index+1, one[1]))print(Style.RESET_ALL)opt=input("\n\t角色编号:")# 根据输入的内容,将其换算为 "角色编号"role_id=result[int(opt)-1][0]__user_service.insert(username, password, email, role_id)print("\n\t保存成功(3秒自动返回)")time.sleep(3)elif opt=="2":page = 1while True:os.system("clear")count_page = __user_service.search_count_page()result = __user_service.search_list(page)for index in range(len(result)):one = result[index]print(Fore.LIGHTBLUE_EX,"\n\t%d\t%s\t%s" % (index + 1, one[1], one[2]))print(Fore.LIGHTBLUE_EX, "\n\t-------------------")print(Fore.LIGHTBLUE_EX, "\n\t%d/%d" % (page, count_page))print(Fore.LIGHTBLUE_EX, "\n\t-------------------")print(Fore.LIGHTRED_EX, "\n\tback.返回上一层")print(Fore.LIGHTRED_EX, "\n\tprev.上一页")print(Fore.LIGHTRED_EX, "\n\tnext.下一页")print(Style.RESET_ALL)opt = input("\n\t输入操作编号:")if opt == "back":breakelif opt == "prev" and page > 1:page -= 1elif opt == "next" and page < count_page:page += 1elif int(opt) >= 1 and int(opt) <= 10:""" 1、这里的 opt 获取到输入的编号是 string 类型,需要先转成 int 类型2、因为每一页的用户数量是十条,所以输入的取值范围是 大于等于1、小于等于103、在获取输入的记录时,这里获取的用户的id并不是数据库中新闻记录的主键id4、传入的记录其实是显示在终端的用户记录的索引,所以我们需要将传入的记录换算为 "用户记录" 的索引位"""os.system("clear")user_id=result[int(opt)-1][0] # 获取终端显示的用户记录索引对应的用户idusername = input("\n\t新用户名:")password = getpass("\n\t新密码:")repassword = getpass("\n\t再次输入密码:")if password!=repassword:print(Fore.LIGHTRED_EX, "\n\t两次密码不一致(3秒自动返回)")print(Style.RESET_ALL)time.sleep(3)breakemail = input("\n\t新邮箱:")result = __role_service.search_list()for index in range(len(result)): # 循环输出 "角色列表" 的结果集one = result[index]print(Fore.LIGHTBLUE_EX, "\n\t%d.%s" % (index + 1, one[1]))print(Style.RESET_ALL)opt = input("\n\t角色编号:")role_id = result[int(opt) - 1][0]opt=input("\n\t是否保存(Y/N)")if opt=="Y" or opt=="y":__user_service.update(user_id, username, password, email, role_id)print("\n\t保存成功(3秒自动返回)")time.sleep(3)elif opt=="3":page = 1while True:os.system("clear")count_page = __user_service.search_count_page()result = __user_service.search_list(page)for index in range(len(result)):one = result[index]print(Fore.LIGHTBLUE_EX,"\n\t%d\t%s\t%s" % (index + 1, one[1], one[2]))print(Fore.LIGHTBLUE_EX, "\n\t-------------------")print(Fore.LIGHTBLUE_EX, "\n\t%d/%d" % (page, count_page))print(Fore.LIGHTBLUE_EX, "\n\t-------------------")print(Fore.LIGHTRED_EX, "\n\tback.返回上一层")print(Fore.LIGHTRED_EX, "\n\tprev.上一页")print(Fore.LIGHTRED_EX, "\n\tnext.下一页")print(Style.RESET_ALL)opt = input("\n\t输入操作编号:")if opt == "back":breakelif opt == "prev" and page > 1:page -= 1elif opt == "next" and page < count_page:page += 1elif int(opt) >= 1 and int(opt) <= 10:""" 1、这里的 opt 获取到输入的编号是 string 类型,需要先转成 int 类型2、因为每一页的用户数量是十条,所以输入的取值范围是 大于等于1、小于等于103、在获取输入的记录时,这里获取的用户的id并不是数据库中新闻记录的主键id4、传入的记录其实是显示在终端的用户记录的索引,所以我们需要将传入的记录换算为 "用户记录" 的索引位"""os.system("clear")user_id=result[int(opt)-1][0]__user_service.delete_by_id(user_id)print("\n\t删除成功(3秒自动返回)")time.sleep(3)elif opt == "back": # 返回上一级层级菜单breakelif opt == "exit": # 安全退出sys.exit(0)else:print("\n\t*****登录失败...3秒后自动返回!*****")time.sleep(3)elif opt=="2":sys.exit(0)# 安全退出 ---> 利用 "exit()" 方法安全退出;(释放数据库连接、文件连接...之后退出)

PS:从上图可以看出,原来 5条 缓存的记录在刷新之后,变成了 2条 。也就是说,我们再执行删除操作的时候,除了实现删除 MySQL 数据库中的新闻记录之外,也实现了删除 Redis 中的缓存记录。

〖Python 数据库开发实战 - Python与Redis交互篇⑫〗- 综合案例 - 新闻管理系统 - 删除新闻(含redis缓存)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。