Python基础编程案例之编写交互式博客系统

1、博客系统的需求描述

利用Python基础内容,编写一个博客系统,涵盖以下功能,后期有需求再优化:

面向用户层面的功能:

  • 文章的发布。
  • 删除文章。
  • 修改文章的内容(包括文章的标题、内容)。
  • 对文章进行评论以及删除文章的某个评论。
  • 阅读文章。
  • 对文章进行点赞、收藏、打赏。
  • 查看某篇博文的属性(文章的总字数、点赞次数、收藏次数、评论次数、打赏次数、打赏收益)。

面向后台管理的功能:

  • 统计文章库共存了多少篇文章。
  • 统计所有博文的字数、文章的点赞数、收藏数、打赏次数。
  • 统计本博客站点的打赏总收益额。

后续学了Python进阶还会优化这个项目。

2、面向用户层面各功能的设计思路与代码编写

2.1.定义文章库

首先定义一个文章库,所有的文章都存在这个文章库中,由于只是Python基础,还不掌握如何与MySQL连接,且不会数据库设计,因此我们以Python中的字典数据类型,去模拟一样文章库。

设计原理:

  • 首先初始状态,是没有任何数据的,因此定义一个空的字典,当用户发布文章后将文章添加到字典库中。
articles = {
    
    }

2.2.文章的发布

文章发布主要用于用户发布文章的,用户发布文章就要考虑到用户发布的文章是不是完整的,例如标题有没有填写,文章内容有没有填写等等,都需要检测。

分为两部分,一部分是文章发布,一部分是检测文章和标题是否有不完整的地方,因此可以定义两个函数,一个函数用于发布文章,另一个函数用于检测文章是否完整,检测文章是否完整的函数会在新增文章里调用。

检测文章标题、内容是否为空的函数设计原理:

  • 定义函数check_title_content(**keyargs),形参是一个个数可变的关键字形参,用于接收文章的标题和内容。
  • 在函数体内判断如果文章的标题和内容都为空的话,那么就输出“请输入文章的标题以及内容”。
  • 如果文章标题的长度为0,就表示文章标题为空,那么就输出“文章标题不能为空”。
  • 如果文章的内容长度为0,就表示文章内容为空,那么就输出“文章内容不能为空”。
  • 个数可变的关键字形参,形参就相当于变量名,变量值就是一个字典,因此在判断标题、内容的长度时,就是看title、content对应的value长度是否为0,如果不明白keyargs的内容具体是啥,可以使用print打印keyargs观察就明白了。
  • 如果文章的内容和长度都不为0,那么就返回一个True。
def check_title_content(**keyargs):
    """
    :param **keyargs用于定义个数可变的关键字形参,因此必须同时传入title和content这两个关键字形参,否则会抛出异常
    """
    if len(keyargs['title']) == 0 and len(keyargs['content']) == 0:
        return '请输入文章的标题以及内容'
    elif len(keyargs['title']) == 0:
        return '文章标题不能为空'
    elif len(keyargs['content']) == 0:
        return '文章内容不能为空'
    return True

新增文章的设计原理:

  • 定义函数add_atricles(),不用传入任何形参。

  • 在函数体内,使用input函数让用户输入文章的标题,然后让用户输入文章的内容。获取用户输入的文章标题和内容后,将其保存在变量里。文章标题保存在title标量里,文章内容保存在content变量里。

  • 然后调用check_title_content(title=title, content=content)函数,传入对应的关键字形参,将用户的标题和内容都传入check_title_content函数中去判断哪一部分为空,为空的一部分就会返回用户哪里为空,如果用户的文章标题和内容都完整,那么就返回一个True。

  • 只需要判断check_title_content函数的返回结果是否为True,如果为True,就说明文章标题和内容都写完整了,可以存储到文章库里,否则就结束函数的运行,避免脏数据写入到文章库。

  • 满足了上面的检测条件后,就可以去生成文章在字典里的键值对元素了:

    • 首先生成文章的ID号,后面删除文章时可以根据ID将文章彻底的删除,因此文章的ID必定是字典中的父级Key。每篇文章的ID都不相同,可以使用len函数计算字典元素的个数,个数+1就是本次文章的ID号。
    • 然后生成文章的属性,一篇文章有很多属性,包括文章的标题、内容、文章字数、点赞数、收藏数、打赏次数、打赏金额、评论等内容,由于文章的属性很多,在设计结构的时候,可以将文章的属性放在一个字典里,这个字典就可以作为ID的Value,也就是子字典,这样一来,文章ID和文章的属性就对应上了。
    • 文章属性子字典中可以暂时设计以下几个键值对元素:
      • title:文章的标题,value来源于用户传入的文章标题变量。
      • content:文章的内容,value来源于用户传入的文章内容变量。
      • words_num:文章的字数,value来源于通过len函数计算文章内容的长度。
      • likes:点赞次数,初始值为0,后面会有单独的函数对文章进行点赞。
      • collects:收藏次数,初始值为0,后面会有单独的函数对文章进行收藏。
      • give_counts:打赏次数,初始值为0,后面会有单独的函数对文章进行打赏,并记录打赏的次数。
      • gives:打赏金额,初始值为0,后面会有单独的函数对文章进行打赏。
      • comments:评论区,文章的评论可能有很多,因此对于评论区的value也定义成一个字典,初始值为空字典,后面会有单独的函数在评论区中添加评论。
    • 然后将文章的ID、文章的属性,以Key和Value的形式,追加到文章字典库中,即可完成文章的添加。
def add_atricles():
    """新增文章"""
    global articles
    # 接收用户写入的文章标题
    title = input('请输入文章的标题:')
    # 接收用户写入的文章内容
    content = input('请输入文章内容:')
    # 检查文章标题以及内容是否为空
    check_resulf = check_title_content(title=title, content=content)
    # 如果为空则结束函数的运行
    if check_resulf != True:
        print(check_resulf)
        return

    # 生成文章的id
    art_id = len(articles) + 1

    # id为字典中的父级Key,value为文章的属性,文章的属性是字典对象,在字典中包含多个键值对,每一个键值对都是文章的属性
    #title为文章标题,content为文章内容,words_num为文章的字数,likes为文章点赞数,collects为文章收藏数,give_counts为文章打赏次数,gives为文章打赏金额,comments为文章的评论区
    #最后将文章ID及对应的文章属性追加到文章字典库
    articles[art_id] = {
    
    
        'title': title,
        'content': content,
        'words_num': len(content),
        'likes': 0,
        'collects': 0,
        'give_counts': 0,
        'gives': 0,
        'c

2.3.删除文章

经过各种函数的调用后,在文章字典库生成的一篇文章内容如下,父级Key是文章的ID,父级Value中是对应的文章属性,包含一系列参数。

image-20220903103320348

当觉得一篇文章写的不如意时,就想着删除文章,下面来设计删除文章的函数,删除文章的函数很简单,重点是要理解这个逻辑。

删除文章的设计原理:

  • 定义函数del_atricles(),不用传入任何形参。
  • 在函数体汇总通过input函数接收用户要删除的文章标题,用户肯定不知道文章的ID是多少,因此用户只能根据文章的标题去删除。将要删除的文章标题存储在title变量里。
  • 由于文章的标题、内容等之类的属性都在articles字典的父级Key的Value里,且父级Key的Value都是子字典,因此可以使用for循环去遍历这个字典,遍历字典时调用items方法,将Key和Value转换成元组,利用元组多变量赋值的特性,每次循环时,将Key赋值给wzid变量,将Value赋值给wzsx变量,这样一来wzsx变量里就包含了文章属性的字典。
  • 我们就可以判断用户输入的文章标题是否在文字属性的字典里存在,如果存在才进行删除,否则就返回要删除的文章不存在,
  • 当用户指定删除的文章在文章属性字典里存在,那么此次循环的wzid变量就是该文章的ID,将其赋值给del_wzid变量,然后调用pop方法删除这个ID,删除了Key,对应的Value也就不存在了,文章也就成功被删除了。
  • 函数只进行一次操作,因此当满足循环体中的if条件后,执行完对应的动作,就结束函数的运行,否则就是一个BUG。
def del_atricles():
    """删除文章"""
    # 接收用户要删除问题的标题
    title = input('请输入要删除的文章标题:')

    #使用for循环去遍历文章字典库,遍历字典时调用items方法,将Key和Value转换成元组,利用元组多变量赋值的特性,每次循环时,将Key赋值给wzid变量,将Value赋值给wzsx变量,这样一来wzsx变量里就包含了文章属性的字典,每次循环时,判断用户要删除的文章是否在文章属性的字典里,如果存在,则找到文章对应的ID,将其在文章字典库中删除,并结束函数的运行,否则就返回要删除的文章不存在
    for wzid, wzsx in articles.items():
        if wzsx['title'] == title:
            del_wzid = wzid
            articles.pop(del_wzid)
            delart_format = '文章:"{t}" 成功删除!'
            print(delart_format.format(t = title))
            return
    else:
        print('要删除的文章不存在!')

2.4.修改文章的标题以及内容

修改文章的标题和内容,在代码上很相似,因此我将这两个功能放在了一个函数了,因为修改文章的标题,也看会去修改文章的内容,那么只要是想对文章进行修改,首先询问要对文章标题进行修改吗,然后在询问要对文章的内容修改吗。

文章的标题修改和内容修改,返回的内容不同,因此将修改文章标题和修改文章内容的操作,分别放在两个函数里。

由于会询问用户是否要对xxx进行修改,因此还需要用户输入一个动作,修改标题和内容的动作都一样,因此通过一个函数来实现。

最后定义一个修改文章的函数,在里面会让用户输入要修改的文章标题,然后会调用捕捉用户动作的函数,在捕捉用户动作的函数中会根据传递的不同类型参数,去执行不同类型的修改操作函数,由于修改文章比较复杂,共用了四个函数。

1)修改文章标题的操作的函数设计原理:

  • 先来定义一个函数title_action_yes(wzsx),这个函数主要是执行修改文章标题的所有操作,其中wzsx形参用于接收for循环文章字典时的wzsx变量,这个函数肯定是在for循环文章字典库之后调用的,否则wzsx将没有实参传递。
  • 首先定义一个变量old_title,用于记录修改标题前的文章标题。
  • 然后使用input函数让用户输入文章新的标题,并赋值给变量new_title
  • 最后根据传入的wzsx变量实参,去修改文章属性字典中Key为’title’的value值,这样一来文章的标题就被更新了。
  • 最后返回给用户文章的新旧标题。
def title_action_yes(wzsx):
    """
    此函数用于修改文章的标题
    :param:wzsx形参用于接收 for循环文章字典articles.items()时的wzsx变量,调用此函数时,就会传入wzsx变量,wzsx变量的对象就是文章属性的字典
    """
    old_title = wzsx['title']
    new_title = input('请输入新的文章标题:')
    wzsx['title'] = new_title
    print('"{o}" 文章的标题已更名为:"{n}"'.format(o=old_title, n=wzsx['title']))

2)修改文章内容的操作的函数设计原理:

修改文章内容的操作与修改文章标题的设计原理一样。

  • 先来定义一个函数content_action_yes(wzsx),这个函数主要是执行修改文章内容的所有操作,其中wzsx形参用于接收for循环文章字典时的wzsx变量,这个函数肯定是在for循环文章字典库之后调用的,否则wzsx将没有实参传递。
  • 首先定义一个变量old_content,用于记录修改标题前的文章标题。
  • 然后使用input函数让用户输入文章新内容,并赋值给变量new_content
  • 最后根据传入的wzsx变量实参,去修改文章属性字典中Key为’content’的value值,这样一来文章的内容就被更新了。
  • 最后返回给用户文章的新旧内容。
def content_action_yes(wzsx):
    """
    此函数用于修改文章的内容
    :param:wzsx形参用于接收 for循环文章字典articles.items()时的wzsx变量,调用此函数时,就会传入wzsx变量,wzsx变量的对象就是文章属性的字典
    """
    old_content = wzsx['content']
    new_content = input('请输入新的文章内容:')
    wzsx['content'] = new_content
    print('"{t}"文章的旧内容为:\n\'\'\'{o}\'\'\' \n文章更新成功,新的内容为:\n\'\'\'{n}\'\'\''.format(t=wzsx['title'], o=old_content, n=wzsx['content']))

3)捕捉用户动作的函数设计原理:

  • 定义函数action(action, type_action, wzsx),此函数共接收三个形参,action用于接收用户输入的动作,type_action用于接收用户修改的类型,是修改标题还是修改文章内容,wzsx用于接收for循环文章字典时的wzsx变量。
  • 首先判断action的值不是yes并且也不是no,如果满足这个条件,就说明用户输入的动作参数不正确,此时就会定义一个for循环,循环三次,也就是说,在三次内,有一次输入的动作参数为yes或者是no,就会去执行对应的代码,如果三次内都没有输入正确,那么就返回参数不合法。
    • for循环会循环3次,在循环体中会让用户输入yes或者no,并且赋值给当action_again变量,第三次循环还没有输入正确的参数时,将会打印参数不合法。
    • 在循环体中,如果用户输入的是yes,那么就判断type_action形参的值,如果这个形参的值为title_action,就说明要对文章的标题进行修改,那么就调用title_action_yes(wzsx)这个函数传入wzsx变量,对文章的标题进行修改,如果type_action形参的值为content_action,说明要对文章的内容进行修改,那么就调用content_action_yes(wzsx)这个函数传入wzsx变量,对文章的内容进行修改,一次处理后使用return结束函数。
    • 在循环体中,如果用户输入的是no,那么就打印不对文章属性进行修改,使用return结束函数。
  • 如果用户一开始就输对了动作参数,当动作参数为yes,如果type_action形参的值为title_action,就说明要对文章的标题进行修改,那么就调用title_action_yes(wzsx)这个函数传入wzsx变量,对文章的标题进行修改,如果type_action形参的值为content_action,说明要对文章的内容进行修改,那么就调用content_action_yes(wzsx)这个函数传入wzsx变量,对文章的内容进行修改,一次处理后使用return结束函数。
  • 如果用户一开始就输对了动作参数,当动作参数为no,那么就打印不对文章属性进行修改,使用return结束函数。
  • 当用户输入的文章不存在时,那么就返回你要修改的文章不存在。
def action(action, type_action, wzsx):
    """
    此函数既可以修改文章的标题,又可以修改文章的内容,主要根据type_action来识别修改的是标题还是内容
    :param action: action的值为yes或者no,如果非yes、no会让用户重新输入,重输入的次数为3,如果重输入时,有一次输对了,那么就会在循环体内根据条件对文章进行修改
    :param type_action: 当type_action的值为title_action时,就会调用修改文章标题的函数执行修改文章标题的相关操作
                        当type_action的值为content_action时,就会调用修改文章内容的函数执行修改文章内容的相关操作
    :param wzsx: 值为wzsx,wzsx是for循环字典库Key和Value中Value部分的内容,wzx包含了所有的文章属性,包括标题、内容等等
    """
    #print(action, type_action, wzsx)  调试使用
    if action != 'yes' and action != 'no':
        # 当action的值不是yes、no时,可以重复输入三次,如果三次输入的都不对,则打印参数不合法,如果三次中有一次输入对了,就会根据对应的动作参数,执行对应的代码,完成文章的修改
        for i in range(1, 4):
            action_again = input('请输入[yes|no]:')
            if action_again == 'yes':
                # 当重复输入过程中输入了yes,则判断type_action的值,如果是title_action则修改文章的标题,调用title_action_yes(wzsx)函数处理,如果是content_action则修改文章的内容,调用函数content_action_yes(wzsx)处理,函数执行完成后使用return跳出循环,结束yes、no的重复
                if type_action == 'title_action':
                    title_action_yes(wzsx)
                    return
                elif type_action == 'content_action':
                    content_action_yes(wzsx)
                    return
            elif action_again == 'no':
                print('不对文章属性进行修改。')
                return
            #重复三次都没有输对,则返回参数不合法,请联系管理员
            else:
                if i == 3:
                    print('参数不合法,请联系管理员~')
    # 当action为yes时,就说明用户一次就输对了操作,判断是对文章标题操作还是对文章的内容操作,然后调用对应的函数,函数执行完后使用return结束
    elif action == 'yes':
        # 对于文章的标题使用title_action_yes函数处理
        if type_action == 'title_action':
            title_action_yes(wzsx)
            return
        # 对于文章的内容使用content_action_yes函数处理
        elif type_action == 'content_action':
            content_action_yes(wzsx)
            return
    elif action == 'no':
        print('不对文章属性进行修改。')
        return

4)修改文章的函数设计原理

这个函数就是修改文章的主函数了,在这个函数中会让用户输入要修改的文章标题,然后去遍历文章字典,当用户输入的文章在后台文章库时,询问用户是否要对文章标题进行修改,如果修改则调用捕捉用户动作的函数完成对文章标题的修改,随后询问用户是否要对文章内容进行修改,如果修改,也调用捕捉用户动作的函数完成对文章内容的修改,当用户输入的文章不存在后台文章库时,则返回你要修改的文章不存在。

  • 定义update_atricles(),不需要传递任何参数。
  • 首先使用input函数,让用户输入要修改的文章标题,然后将标题赋值给title变量。
  • 接下来进行for循环遍历,遍历文章字典库,取到文章的id以及文章属性的变量,和前面的删除文章一个套路。
  • 然后判断用户传入的文章是否在后台的文章字典库中,如果存在,那么就使用input函数“返回文章存在,是否要对文章的标题进行修改”,让用户传入一个动作,该动作会赋值给action_format变量。
  • 然后调用action(action = title_action, type_action = 'title_action', wzsx = wzsx)函数,传入这些实参,完成对文章标题的修改。
  • 标题、内容都修改完成后,使用return结束函数。
  • 当文章标题修改完成后,开始询问用户是否要对文章的内容进行修改,套路都一样。
def update_atricles():
    """修改文章"""
    title = input('请输入要修改的文章标题:')
    #循环遍历文章字典库,将文章的id(Key)放在wzid变量里,将文章的属性(Value)放在wzsx变量里
    for wzid, wzsx in articles.items():
        #修改文章的标题
        if wzsx['title'] == title:
            #up_wzid = wzid
            #print('要修改的文章id:', up_wzid)
            #input函数只能输入一个参数,当需要输入两个参数时,可以使用格式化字符串
            action_format = '后台查询到{t}文章存在,是否要对文章标题进行修改[yes|no]:'
            title_action = input(action_format.format(t=wzsx['title']))
            action(action = title_action, type_action = 'title_action', wzsx = wzsx)

            #随后询问用户是否也要对这个标题对应的文章进行修改
            content_format = '"{t}"的文章内容为:\n{c} \n是否要对文章内容进行修改[yes|no]:'
            content_action = input(content_format.format(t=wzsx['title'], c=wzsx['content']))
            action(action = content_action, type_action = 'content_action', wzsx = wzsx)
            return
    else:
        print('你要修改的文章不存在!')

2.5.在评论区添加评论

接下来设计文章的评论区,一片文章一般会有0~n条评论,因此如果将每条评论的都已键值对的形式存储在文章ID对应的Value子字典里,势必会导致子字典很长,太臃肿,因此一开始在设计文章的字典库时,就将评论区以字典的方式进行了存储,如下图所示,文章的ID是父级Key,父级Key的Value是文章的所有属性,父级Key的Value是一个字典,评论区是文章的一种属性,其对于的Key也是一个字典,在这个字典中n个Key,每个Key的Value都是一条评论。

image-20220903144341009

对文章进行评论的函数设计原理:

  • 定义函数add_comment(),不需要传递任何参数。

  • 首先让用户输入对哪篇文章进行评论,然后将文章的标题存储到title变量里。

  • 然后使用老套路,通过for循环遍历文章字典库,每次循环时将文章的属性放在wzsx变量里。

  • 判断用户输入的文章是否在文章字典库中,如果存在,则让用户输入要发表的评论.

  • 一个文章可能存在多条评论内容,我们不能确定评论有多少条,所有的评论虽然都在字典中充当Value,但是Value总要对应Key的,评论对应的Key可以由comment+当前评论的ID组成,因此接下来需要生成生成评论的ID,评论的ID可以通过len函数计算comments的Value中字典共有多少个元素,计算出来的数+1就是当前评论的ID,文章中每条评论的ID都不同。生成完评论的ID后,再生成本次评论的Key,评论的Key由comment+评论ID组成。

  • 评论内容、本次评论的Key名都准备完成后,就可以在评论区字典中增加评论键值对,完成评论的发表,然后使用return结束函数。

  • 当用户输入的文章不存在时,则返回你要评论的文章不存在。

另外这里再提一点,为什么不接着使用for循环去遍历评论区的字典,然后追加评论到字典里,那是因为评论区位于文章属性字典里,文章属性的字典里只有这一个元素的Value是一个字典,因此不能再使用for循环去遍历评论区字典,另外一个文章可能在添加评论之前,是没有评论的,也就意味着评论区为空,也是无法去循环遍历的。

评论区的字典相当于文章字典的子字典,因此可以使用二维字典的方法去追加元素:wzsx['comments'][comment_key] = comment

def add_comment():
    """
    对某个文章进行评论
    """
    title = input('请输入要对哪篇文章进行评论:')
    for wzid, wzsx in articles.items():
        #对文章进行评论
        if wzsx['title'] == title:
            comment = input('请发表评论:')
            #生成当前评论的ID号,每条评论的ID不同,当前评论区的评论数+1就是当前评论的ID号
            comment_id = len(wzsx['comments']) + 1
            #生成当前评论所在字典中的Key,由comment+评论ID组成
            comment_key = 'comment' + str(comment_id)
            #在评论区添加评论
            wzsx['comments'][comment_key] = comment
            #wzsx['comment']['comment' + str(comment_id)]= comment
            return
    else:
        print('你要评论的文章不存在!')

2.6.删除文章中的某条评论

删除评论和发表评论也很像,但是删除评论时就可以使用for循环遍历评论区的字典,因为此时字典中肯定有评论。

  • 定义函数del_comment(),不需要传递任何参数。
  • 首先使用inpu函数,让用户输入要对哪篇文章的评论进行删除,将文章的标题赋值给title变量。
  • 然后使用for循环遍历文章字典库,获取文章属性的字典,赋值给wzsx变量,当要删除评论的文章存在于字典库时,就让用户输入要删除那条评论,并将其存储在comment变量中:
    • 此时就再使用for循环遍历评论区字典wzsx['comments'].items(),当要删除的评论在评论区时,就使用pop方法删除这条评论,否则就提示要删除的评论不存在,只要删除了评论,就使用return结束函数的运行。
  • 如果文章不存在,则返回你要删除评论的文章不存在。
def del_comment():
    """删除对某发个文章的某条评论"""
    title = input('请输入要对哪篇文章的评论进行删除:')
    for wzid, wzsx in articles.items():
        #判断要删除评论的文章存在否
        if wzsx['title'] == title:
            comment = input('请输入要删除的评论:')
            #遍历comment评论的字典,判断删除的那条评论是否存在,如果存在则删除,否则返回评论不存在
            for comkey,comvalue in wzsx['comments'].items():
                if comvalue == comment:
                    wzsx['comments'].pop(comkey)
                    comdelformat = '"{t}"文章中的"{c}"评论已被删除。'
                    print(comdelformat.format(t=title, c=comvalue))
                    #对字典中的键值对进行修改后,记得跳出循环,否则就会抛出异常:dictionary changed size during iteration
                    return
            else:
                print('要删除的评论不存在!')
            #if中包含了for,for中又包含了if,为了避免多次循环,第一个if满足条件后,就return结束函数
            return
    else:
        print('你要删除评论的文章不存在!')

2.7.阅读文章

阅读文章的函数设计原理:

  • 定义函数search_atricles(),不传入任何参数。

  • 使用input函数让用户输入要阅读的文章,然后赋值给title变量。

  • 使用for循环去遍历文章字典库,当文章的标题在文章属性字典中存在时,就返回文章的内容,否则就打印要阅读的文章不存在。

  • 当文章存在时,就将文章属性字典中的content的Value使用get方法打印出来。

def search_atricles():
    """阅读某篇文章"""
    title = input('请输入要阅读的文章:')
    for wzid, wzsx in articles.items():
        if wzsx['title'] == title:
            search_format = '"{t}"文章的内容为:\n{c}'
            print(search_format.format(t = wzsx['title'], c = wzsx.get('content')))
            return
    else:
        print('要阅读的文章不存在!')

2.8.对文章进行点赞

对文章点赞的函数设计原理:

  • 定义函数atr_like(),不传入任何参数。
  • 使用input函数让用户输入要点赞的文章,然后赋值给title变量。
  • 使用for循环去遍历文章字典库,当文章的标题在文章属性字典中存在时,就对文章进行点赞,否则就提示要点赞的文章不存在。
  • 当文章存在时,就将文章属性字典中likes的Value值+1,实现累加的效果,并返回点赞成功,然后使用return结束函数。
def atr_like():
    """对指定的文章点赞"""
    title = input('请输入要点赞的文章:')
    for wzid, wzsx in articles.items():
        if wzsx['title'] == title:
            wzsx['likes'] += 1
            print('点赞成功~')
            return
    else:
        print('要点赞的文章不存在!')

2.9.对文章进行收藏

对文章点赞的函数设计原理:

  • 定义函数atr_collect(),不传入任何参数。
  • 使用input函数让用户输入要收藏的文章,然后赋值给title变量。
  • 使用for循环去遍历文章字典库,当文章的标题在文章属性字典中存在时,就对文章进行收藏,否则就提示要收藏的文章不存在。
  • 当文章存在时,就将文章属性字典中collects的Value值+1,实现累加的效果,并返回收藏成功,然后使用return结束函数。
def atr_collect():
    """对指定的文章收藏"""
    title = input('请输入要收藏的文章:')
    for wzid, wzsx in articles.items():
        if wzsx['title'] == title:
            wzsx['collects'] += 1
            print('收藏成功~')
            return
    else:
        print('要收藏的文章不存在!')

2.10.对文章进行打赏

  • 定义函数atr_give(),不需要传入任何参数。
  • 使用input函数让用户输入要打赏的文章,然后赋值给title变量。
  • 使用for循环去遍历文章字典库,当文章的标题在文章属性字典中存在时,就对文章进行打赏,否则就提示要打赏的文章不存在。
  • 当文章存在时,就让用户输入打赏的金额,然后判断打赏的金额是否是数字,如果是数字的话,将打赏的金额转换成小数,并且将文章属性字典中gives的Value值+打赏的金额,并且将打赏次数也+1,即对文章属性字典中give_counts的Value值+1,实现打赏金额、打赏次数累加的效果。另外当打赏的金额不是数字时,提示输入正确的打赏金额。
  • 打赏完成后使用return结束函数的运行。
def atr_give():
    """对指定的文章打赏"""
    title = input('请输入要打赏的文章:')
    for wzid, wzsx in articles.items():
        if wzsx['title'] == title:
            give_format = '请输入要对{t}文章打赏的金额:'
            give = input(give_format.format(t = title))
            # 如果打赏的金额是数字,那么就将其转换成小数,然后将金额和当前字典中give的value进行累加,将历次打赏的金额都累加在一起,并且每次打赏,打赏次数+1
            if give.isdigit():
                wzsx['gives'] += float(give)
                wzsx['give_counts'] += 1
                print('打赏成功~')
                return
            else:
                print('请输入正确的打赏金额!')
                return
    else:
        print('要打赏的文章不存在!')

2.11.查询指定文章的属性

用户可以浏览一片文章的属性,例如文章的总字数、点赞次数、收藏次数、评论次数、打赏次数、收藏次数。

  • 定义函数search_atr_pro(),不需要传入任何参数。
  • 使用input函数让用户输入要收藏的文章,然后赋值给title变量。
  • 使用for循环去遍历文章字典库,当文章的标题在文章属性字典中存在时,就打印文章的属性,否则就提示文章不存在。
  • 文章的属性都位于文章字典库的文章属性字典里,直接打印即可,对于评论次数可以使用len函数取获取。
def search_atr_pro():
    """查看指定文章的属性"""
    title = input('请输入要查看属性的文章:')
    for wzid, wzsx in articles.items():
        if wzsx['title'] == title:
            pro_format = '"{t}"文章的总字数为{w}、点赞次数为"{l}、收藏次数为{c}、评论次数为{csc}、打赏次数为{gc}、打赏收益为{gv}'
            print(pro_format.format(t = wzsx['title'], w = wzsx['words_num'], l = wzsx['likes'], c = wzsx['collects'], csc = len(wzsx['comments'].values()) , gc = wzsx['give_counts'], gv = wzsx['gives']))
            return
    else:
        print('要查看属性的文章不存在!')

3、面向后台管理层面各功能的设计思路与代码编写

3.1.统计后台文章的数量

非常简单,只需要通过len函数获取文章字典库的元素个数即可。

def atricles_nums():
    """统计后台文章数量"""
    atr_count = len(articles)
    print('后台文章字典库共有"{}"篇文章。'.format(atr_count))

3.2.文章数据查询

该功能可以统计所有博文的点赞次数、所有博文的收藏次数、所有博文的打赏次数、所有博文的评论次数、所有博文的总字数、所有博文的总收益额。

所有功能的实现套路都一样,都是数据查询,仅说一个所有博文的点赞次数是如何实现的。

  • 定义函数sta_art(status),这个函数需要传入参数,因为每个统计的功能都集成在了这一个函数里,status的取值范围:1为所有博文点赞次数,2为所有博文收藏次数,3为所有博文打赏次数,4、所有博文的评论次数,5为所有博文总字数, 6为博文总收益额
  • 当status等于1的时候,就是对所有博文的点赞数进行统计,首先定义一个初始的总点赞数变量,值为0,然后使用for循环遍历文章字典库,取出每篇博文的点赞数,与总点赞数变量相加,即可得到总点赞次数。
def sta_art(status):
    """根据传的参数判断要统计的项目,1为所有博文点赞次数,2为所有博文收藏次数,3为所有博文打赏次数,4、所有博文的评论次数,5为所有博文总字数, 6为博文总收益额"""
    if status == 1:
        total_likes = 0
        for wzid, wzsx in articles.items():
            total_likes += wzsx['likes']
        tl_format = '所有博客累计点赞次数为:"{tl}"'
        print(tl_format.format(tl = total_likes))
    elif status == 2:
        total_collects = 0
        for wzid, wzsx in articles.items():
            total_collects += wzsx['collects']
        tc_format = '所有博客累计收藏次数为:"{tc}"'
        print(tc_format.format(tc = total_collects))
    elif status == 3:
        total_gcs = 0
        for wzid, wzsx in articles.items():
            total_gcs += wzsx['give_counts']
        gcs_format = '所有博客累计打赏次数为:"{gcs}"'
        print(gcs_format.format(gcs = total_gcs))
    elif status == 4:
        total_csc = 0
        for wzid, wzsx in articles.items():
            total_csc += len(wzsx['comments'])
        csc_format = '所有博客累计评论次数为:"{csc}"'
        print(csc_format.format(csc = total_csc))
    elif status == 5:
        total_fc = 0
        for wzid, wzsx in articles.items():
            total_fc += wzsx['words_num']
        fc_format = '所有博客累计文字数为:"{fc}"'
        print(fc_format.format(fc = total_fc))
    elif status == 6:
        total_earn = 0
        for wzid, wzsx in articles.items():
            total_earn = total_earn + wzsx['gives']
        ear_format = '博客打赏累加收益额为:"{te}"'
        print(ear_format.format(te=total_earn))
    else:
        print('参数不正确!')

4.格式化打印文章字典库

atr_db = json.dumps(articles, indent=4,ensure_ascii=False, sort_keys=False,separators=(',', ':'))
print(atr_db)

5、功能验收

5.1.面向用户层面的各功能验收

#发布文章
add_atricles()
add_atricles()
add_atricles()

#删除指定的文章
del_atricles()

#修改指定的文章
update_atricles()

#对指定的文章发表评论
add_comment()
add_comment()
add_comment()
add_comment()

#对指定的文章删除评论
del_comment()

#阅读指定的文章
search_atricles()

#对指定的文章点赞
atr_like()
atr_like()

#对指定的文章收藏
atr_collect()
atr_collect()

#对指定的文章打赏
atr_give()
atr_give()
atr_give()

#查询指定文章的属性
search_atr_pro()

输出的内容:

D:\软件\Python\python.exe G:/Python全栈运维开发/Python-基础语法/代码文件/简单的个人博客小系统b3.py
简单的个人博客系统
请输入文章的标题:第一篇文章
请输入文章内容:在定义函数时,我们可以强制某个形参必须使用关键字传参,如果不用关键字传参则会抛出异常。
请输入文章的标题:第二篇文章
请输入文章内容:强制某个形参使用关键字传参,做法也很简单,只需要在形参的前面添加一个`*`号,这样一来,`*`号后面所有的形参都会被设置成强制关键字传参,只能接受关键字传参过来的实参。
请输入文章的标题:第三篇文章
请输入文章内容:哈哈哈
请输入要删除的文章标题:第三篇文章
文章:"第三篇文章" 成功删除!
请输入要修改的文章标题:第一篇文章
后台查询到第一篇文章文章存在,是否要对文章标题进行修改[yes|no]:yes
请输入新的文章标题:第①篇:Python函数中的星号参数
"第一篇文章" 文章的标题已更名为:"第①篇:Python函数中的星号参数"
"第①篇:Python函数中的星号参数"的文章内容为:
在定义函数时,我们可以强制某个形参必须使用关键字传参,如果不用关键字传参则会抛出异常。 
是否要对文章内容进行修改[yes|no]:yes
请输入新的文章内容:定义函数时,如果无法事先确定传递的位置实参的个数,在这种情况下,可以将形参定义为个数可变的位置形参,去接收0个或多个实参,传进来的多个实参最终会被转换成一个元组类型,赋值给形参变量。
"第①篇:Python函数中的星号参数"文章的旧内容为:
'''在定义函数时,我们可以强制某个形参必须使用关键字传参,如果不用关键字传参则会抛出异常。''' 
文章更新成功,新的内容为:
'''定义函数时,如果无法事先确定传递的位置实参的个数,在这种情况下,可以将形参定义为个数可变的位置形参,去接收0个或多个实参,传进来的多个实参最终会被转换成一个元组类型,赋值给形参变量。'''
请输入要对哪篇文章进行评论:第①篇:Python函数中的星号参数
请发表评论:大佬写的太好了,感谢分享
请输入要对哪篇文章进行评论:第①篇:Python函数中的星号参数
请发表评论:学到新技术了
请输入要对哪篇文章进行评论:第①篇:Python函数中的星号参数
请发表评论:彩
请输入要对哪篇文章进行评论:第①篇:Python函数中的星号参数
请发表评论:6666
请输入要对哪篇文章的评论进行删除:第①篇:Python函数中的星号参数
请输入要删除的评论:6666
"第①篇:Python函数中的星号参数"文章中的"6666"评论已被删除。
请输入要阅读的文章:第①篇:Python函数中的星号参数
"第①篇:Python函数中的星号参数"文章的内容为:
定义函数时,如果无法事先确定传递的位置实参的个数,在这种情况下,可以将形参定义为个数可变的位置形参,去接收0个或多个实参,传进来的多个实参最终会被转换成一个元组类型,赋值给形参变量。
请输入要点赞的文章:第①篇:Python函数中的星号参数
点赞成功~
请输入要点赞的文章:第①篇:Python函数中的星号参数
点赞成功~
请输入要收藏的文章:第①篇:Python函数中的星号参数
收藏成功~
请输入要收藏的文章:第①篇:Python函数中的星号参数
收藏成功~
请输入要打赏的文章:第①篇:Python函数中的星号参数
请输入要对第①篇:Python函数中的星号参数文章打赏的金额:777
打赏成功~
请输入要打赏的文章:第①篇:Python函数中的星号参数
请输入要对第①篇:Python函数中的星号参数文章打赏的金额:67
打赏成功~
请输入要打赏的文章:第①篇:Python函数中的星号参数
请输入要对第①篇:Python函数中的星号参数文章打赏的金额:25
打赏成功~
请输入要查看属性的文章:第①篇:Python函数中的星号参数
"第①篇:Python函数中的星号参数"文章的总字数为43、点赞次数为"2、收藏次数为2、评论次数为3、打赏次数为3、打赏收益为869.0
{
    "1":{
        "title":"第①篇:Python函数中的星号参数",
        "content":"定义函数时,如果无法事先确定传递的位置实参的个数,在这种情况下,可以将形参定义为个数可变的位置形参,去接收0个或多个实参,传进来的多个实参最终会被转换成一个元组类型,赋值给形参变量。",
        "words_num":43,
        "likes":2,
        "collects":2,
        "give_counts":3,
        "gives":869.0,
        "comments":{
            "comment1":"大佬写的太好了,感谢分享",
            "comment2":"学到新技术了",
            "comment3":""
        }
    },
    "2":{
        "title":"第二篇文章",
        "content":"强制某个形参使用关键字传参,做法也很简单,只需要在形参的前面添加一个`*`号,这样一来,`*`号后面所有的形参都会被设置成强制关键字传参,只能接受关键字传参过来的实参。",
        "words_num":84,
        "likes":0,
        "collects":0,
        "give_counts":0,
        "gives":0,
        "comments":{
    
    }
    }
}

进程已结束,退出代码0

image-20220903164414183

5.2.面向后台管理层面的功能验收

#查询指定文章的属性
search_atr_pro()

#统计后台文章的数量
atricles_nums()

#查询所有博文的点赞次数
sta_art(1)

#查询所有博文的收藏次数
sta_art(2)

#查询所有博文的打赏次数
sta_art(3)

#查询所有博文的评论次数
sta_art(4)

#查询所有博文的总字数
sta_art(5)

#查询所有博文的总收益额
sta_art(6)

image-20220903165031998

6、增加博客导航

博客应该存在一个导航页面,用户根据博客的功能进行一系列的操作。

def main():
    menu_format = '===============================================================================' \
                  '\n={project}=' \
                  '\n={sep}{add_atricles}{sep}{del_atricles}{sep}{update_atricles}{sep}=' \
                  '\n={sep}{add_comment}{sep}{del_comment}{sep}{search_atricles}{sep}=' \
                  '\n={sep}{atr_like}{sep}{atr_collect}{sep}{atr_give}{sep}=' \
                  '\n={sep}{search_atr_pro}{sep}{del_comment}{sep}{search_atricles}{sep}=' \
                  '\n={sep}{add_comment}{sep}{atricles_nums}{sep}{sta_art}{sep}=' \
                  '\n={sep}{search_all}{sep}{quit}{sep}{sep}{sep} =' \
                  '\n==============================================================================='
    print(menu_format.format(project='[Python博客系统]'.center(75, '·'), sep=' '.ljust(10, ' '),
                             add_atricles='1-->发布文章'.ljust(10, ' '), del_atricles='2-->删除文章'.ljust(10, ' '),
                             update_atricles='3-->修改文章 '.ljust(10, ' '),
                             add_comment='4-->发表评论'.ljust(10, ' '), del_comment='5-->删除评论'.ljust(10, ' '),
                             search_atricles='6-->阅读文章'.ljust(10, ' '),
                             atr_like='7-->点赞文章'.ljust(10, ' '), atr_collect='5-->收藏文章'.ljust(10, ' '),
                             atr_give='6-->打赏文章'.ljust(10, ' '),
                             search_atr_pro='8-->文章属性'.ljust(10, ' '), atricles_nums='9-->总文章量'.ljust(10, ' '),
                             sta_art='6-->后台统计'.ljust(10, ' '),
                             search_all='13-->所有文章'.ljust(10, ' '), quit='q-->退出博客系统').ljust(10, ' '))

7、使用博客系统

while True:
    main()
    oper = input('你要进行什么操作:')
    print(oper)
    if oper == "1":
        add_atricles()
    elif oper == "2":
        del_atricles()
    elif oper == "3":
        update_atricles()
    elif oper == "4":
        add_comment()
    elif oper == "5":
        del_comment()
    elif oper == "6":
        search_atricles()
    elif oper == "7":
        atr_like()
    elif oper == "8":
        atr_collect()
    elif oper == "9":
        atr_give()
    elif oper == "10":
        search_atr_pro()
    elif oper == "11":
        atricles_nums()
    elif oper == "12":
        sta_art(1)
        sta_art(2)
        sta_art(3)
        sta_art(4)
        sta_art(5)
        sta_art(6)
    elif oper == "13":
        atr_db = json.dumps(articles, indent=4, ensure_ascii=False, sort_keys=False, separators=(',', ':'))
        print(atr_db)
    elif oper == "q":
        exit('期待下次使用博客系统~')
    else:
        print('参数不合法,请联系管理员!')

8、使用过程

image-20220903224525225

猜你喜欢

转载自blog.csdn.net/weixin_44953658/article/details/131758981