这一篇教程,我们完成简单的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功能(下)