最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

练习项目14:简单的BBS功能(下)

Python教程 小楼一夜听春语 10333浏览 0评论

这一篇教程,我们完成简单的BBS功能第二阶段。

首先,通过一些截图我们看一下,我们的任务目标。

最终的首页:

消息查看页:

消息编辑页:

消息保存页:

大家所看到的一共有4个页面,分别是:

  • 首页:消息列表,可以点击消息标题查看消息,也可点击发布消息链接发布新消息;
  • 消息查看页:查看消息内容,并且可以点击回复消息进行回复;
  • 消息编辑页:可以发布新的消息,也可以回复其它消息。
  • 消息保存页:对编辑的消息进行保存。

根据这四个页面的功能,我们的编写代码时也分为四个脚本文件。

一、首页(main.py)

这个页面,我们需要将消息列表显示出来。

并且,需要提供一个发布消息的文字链接,能够进入消息编辑页。

显示消息列表的内容,我们需要查询出数据库中所有的消息内容,并参照上一篇教程的实现,将消息内容有层级的显示在页面上。

示例代码:

import psycopg2.extras

conn = psycopg2.connect(database='myproject_db', user='opython', password='opython')
curs = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

print('''
<!DOCTYPE html>
<html lang="zh_cn">
<head>
    <meta charset="gbk">
    <title>我的论坛</title>
</head>
<body>
    <h3>小楼帅哥的第一个BBS</h3>
''')

sql = 'select * from messages'
curs.execute(sql)
messages = curs.fetchall()
top_level = []
children = {}
for message in messages:
    parrent_id = message['reply_to']
    if parrent_id is None:
        top_level.append(message)
    else:
        children.setdefault(parrent_id, []).append(message)


def format_show(message):  # 创建递归函数
    print('<h5><a href="view.py?id=%(id)i">%(sender)s:%(subject)s</a></h5>' % message) 
    print('<font size="2">{}</font>'.format(message['text']))
    try:
        kids = children[message['id']] 
    except KeyError:
        pass
    else:
        print('<blockquote>')
        for kid in kids:
            format_show(kid)
        print('</blockquote>')

for message in top_level:  # 遍历顶级消息列表
    format_show(message)  # 调用递归函数

print('''
<hr/>
<a href="edit.py"><font size="2">发布消息</font></a>
</body>
</html>
''')

在上方代码中,因为点击消息标题需要跳转到消息查看页,我们需要为消息标题加上链接,并且在链接中加入消息的id。

消息查看页的名称是“view.py”,所以链接为:view.py?id=%(id)i。

这是一个相对路径,它能够在与当前文件(main.py)同一目录下找到名为“view.py”的文件将其打开。

链接中的问号“?”,表示后方内容为参数变量和值,“=”前方的“id”是变量,后方的“%(id)i”是值。

“%(id)i”中的“%i”表示这里需要插入一个十进制的整数,“(id)”则能够从“message”字典中获取到。

通过这样的处理,我们在打开“view.py”文件的时候,就能够通过cgi模块获取消息id。

二、消息查看页(view.py)

这个页面中,我们需要根据从首页传过来的id,显示相应的消息内容。

示例代码:

import cgi, sys, psycopg2.extras

form = cgi.FieldStorage()
id = form.getvalue('id')  # 获取URL中的id参数

conn = psycopg2.connect(database='myproject_db', user='opython', password='opython')
curs = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)

print('''
<!DOCTYPE html>
<html lang="zh_cn">
<head>
    <meta charset="gbk">
    <title>查看消息</title>
</head>
<body>
''')
try:
    id = int(id)  # 将id转换为整数类型
except:  # 如果转换异常
    print('无效的消息id!')
    sys.exit()  # 退出脚本执行

sql = 'select * from messages where id=%i' % id
curs.execute(sql)
rows = curs.fetchall()
if not rows:  # 如果没有查询结果
    print('消息不存在!')
    sys.exit()  # 退出脚本执行
row = rows[0]  # 获取查询结果中的第一个字典
print('''
<p>
<h5>%(subject)s</h5>
<font size="2">%(sender)s</font></br>
<pre>%(text)s</pre>
</p>
<hr/>
<a href="main.py"><font size="2">返回首页</font></a>|
<a href="edit.py?reply_to=%(id)s"><font size="2">回复消息</font></a>
</body>
</html>
''' % row)

在上方代码中,HTML末尾部分,需要加入两个文字链接,分别能够返回首页和回复消息。

返回首页的链接,可以在<a>标签的“href”属性中直接填入相对路径“main.py”。

回复消息的链接,需要能够打开“edit.py”并且将被回复消息的id通过URL中的参数“reply_to”进行传递。

三、消息编辑页(edit.py)

不管是新发布的消息,还是回复的消息,都能够在这个页面进行编辑。

区别在于,新发布的消息,无需做什么处理;而回复的消息要获取URL中传入的“reply_to”参数内容,根据被回复消息的id自动填入标题(见本文开头的截图),并且在发布消息的时候,还要将这个id传入“save.py”,也就是保存消息页。

示例代码:

import sys, cgi, psycopg2.extras

form = cgi.FieldStorage()
reply_to = form.getvalue('reply_to')  # 获取被回复消息的id
subject = ''  # 创建标题变量

print('''
<!DOCTYPE html>
<html lang="zh_cn">
<head>
    <meta charset="gbk">
    <title>编辑消息</title>
</head>
<body>
<form action="save.py" method="post">
''')  # 创建HTML基本代码并添加表单
if reply_to is not None:  # 如果获取到被回复消息的id
    try:
        reply_to = int(reply_to)  # 将id转换为整数类型
    except:  # 如果转换发生异常
        print('无法回复该消息!')
        sys.exit()  # 退出脚本执行
    else:  # 如果id可用
        print('    <input type="hidden" value="%s" name="reply_to"/>' % reply_to)  # 将被回复消息id写入表单元件值
        conn = psycopg2.connect(database='myproject_db', user='opython', password='opython')
        curs = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
        sql = 'select subject from messages where id=%i' % reply_to  # 通过被回复消息id查询被回复消息的标题
        curs.execute(sql)
        subject = curs.fetchone()[0]  # 将查询到的标题存入变量
        if not subject.startswith('回复:'):  # 如果标题开头没有“回复:”字样
            subject = '回复:' + subject  # 为标题添加“回复:”字样

print('''
    <b><font size="2">主题:</font></b><br/>
    <input type="text" value="%s"  style="width:240px" name="subject"/><br/>
    <b><font size="2">作者:</font></b><br/>
    <input type="text"  style="width:240px" name="sender"/><br/>
    <b><font size="2">编辑内容:</font></b><br/>
    <textarea rows="5" cols="50" style="width:240px" name="text"></textarea><br/>
    <input type="submit" value="发布">
</form>
<hr/>
<a href="main.py"><font size="2">返回首页</font></a>
</body>
</html>
''' % subject)

上方代码运行时,会显示一个消息编辑页面,点击提交按钮时,会将表单数据交由“save.py”进行处理。

四、消息保存页(save.py)

这个页面需要将获取的表单内容插入到数据库的数据表中。

如果是发布新消息,需要提供“subject”、“sender”和“text”三个字段内容。

而如果是回复消息,在插入数据表时,还需要提供“reply_to”字段。

那么,是不是回复消息,我们可以从表单中尝试获取“reply_to”的值,如果能够获取到id,就是回复消息,如果获取到的是None,则是新发布的消息。

另外,在这个页面中,我们还需要对字段中的单引号“’”进行处理,因为SQL语句中的字符串字段会带有单引号,如果字段值中的单引号不做处理,将会引发异常。如果在字段值中有单引号的话,我们需要用两个单引号来表示。

示例代码:

import sys, cgi, psycopg2

def quote(string):  # 定义处理单引号的函数
    if string:  # 如果不是空值或None值
        return string.replace("'", "''")  # 将单引号替换为两个单引号
    else:
        return string

form = cgi.FieldStorage()
subject = quote(form.getvalue('subject'))  # 获取字段值并进行单引号处理
sender = quote(form.getvalue('sender'))  # 获取字段值并进行单引号处理
reply_to = form.getvalue('reply_to')
text = quote(form.getvalue('text'))  # 获取字段值并进行单引号处理
if reply_to is not None:  # 如果有被回复消息的id
    try:
        reply_to = int(reply_to)  # 将id转换为整数类型
    except:  # 如果转换异常
        print('''
        <font size="2" color="red">无法发布该消息!</font>
        <hr/>
        <a href="main.py"><font size="2">返回首页</font></a>
        ''')
        sys.exit()  # 退出脚本执行
if not (subject and sender and text):  # 如果有任何一个字段值为空值或者None值
    print('''
    <font size="2" color="red">请输入回复内容!</font>
    <hr/>
    <a href="edit.py?reply_to=%s"><font size="2">返回编辑</font></a>
    ''' % reply_to)
else:  # 如果是符合要求的输入
    conn = psycopg2.connect(database='myproject_db', user='opython', password='opython')
    curs = conn.cursor()
    if reply_to is None:  # 如果是回复消息
        sql = "insert into messages(subject,sender,text) values('%s','%s','%s')" % (subject, sender, text)
    else:  # 如果是新发布消息
        sql = "insert into messages(subject,sender,reply_to,text) values('%s','%s','%i','%s')" % (
            subject, sender, reply_to, text)
    curs.execute(sql)
    conn.commit()
    print('''
    <font size="2" color="green">发布成功!</font>
    <hr/>
    <a href="main.py"><font size="2">返回首页</font></a>
    ''')

完成以上各部分代码之后,这个简单的BBS功能就全部完成了。

本节练习源代码:【点此下载

转载请注明:魔力Python » 练习项目14:简单的BBS功能(下)

头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)