项目来自python 基础教程的项目七
项目介绍
这个项目使用 python cgi结合MySQL完成了一个类似公告板功能的web应用
项目的再次实现
项目的再次实现将程序分为四个部分:
main.py:相当于主页,实现的功能有:层次的显示所有消息的主题,将主题的内容链接到view.pu,传递主题的id
viem.py:根据cgi传递的id显示主题的内容,链接到edit.py;传递本条消息的id转为回复内容的reply_to
edit.py:编辑输入窗口,输入后将内容传递给save.py保存到数据库
save.py:接收内容,写入数据库
cgi:通用网关接口,是python运行web服务器交换数据的;web服务器通过它将查询提供给程序(自己写的python),再通过网页的形式显示。cgi脚本的输入通常使用表单;也可以使用类似?&id = 2的方式。
使用cgi;
第一步:建立web服务器:python -m http.server --cgi
第二步:# !/usr/bin/python 告诉服务器python解析
第三步:编写cgi程序 如下
main.py
# !/usr/bin/python
print("Content-Type:text/html\n")
import pymysql
import cgitb;cgitb.enable()#调试模块,错误可以打印在网页上
"""
此为主页面;主要功能有二
按照結構展示主題和回復結構
链接到view.py显示每一条消息的内容
"""
ip = '127.0.0.1'
db = 'billbord'
user = 'root'
port = 3308
passwrd = 'PSPS2053'
conn = pymysql.connect(host =ip,db = db,user = user,port = port,passwd=passwrd)
curs = conn.cursor(cursor=pymysql.cursors.DictCursor) #设置返回内容为字典的形式
print("""
<html>
<head>
<title>The FooBar Bulletin Board</title>
</head>
<body>
<h1>The FooBar Bulletin Board</h1>
""")
curs.execute('SELECT * FROM message')
# rows = curs.dictfetchall() mymysql不支持dictfetchall(),pymysql是在游标设置的
rows = curs.fetchall()
toplevel = []
children = {}
#根据reply_to判断是否为回复的消息,如果不是回复,则为顶层消息;如果是恢复,确定其层级
for row in rows:
parent_id = row['reply_to']
if parent_id is None:
toplevel.append(row)
else:
children.setdefault(parent_id, []).append(row) #如果键不存在则插入值为默认值的键,就是有就插入没有就创建
#如果是回复的消息,则添加到children字典中
def format(row):
"""此方法实现了对消息和回复的显示,如果有回复消息,则递归调用显示"""
print('<p><a href="view.py?id={id}">{subject}</a></p>'.format(id = row['id'],subject = row['subject']))
#以链接的形式返回主题,并且链接到view.py,get的方式,以键值对的形式传递参数
try: kids = children[row['id']] #是否有回复消息,如果有,则递归调用回复消息,打印引用消息
except KeyError: pass
else:
print('<blockquote>')
for kid in kids:
format(kid)
print('</blockquote>')
print("""<p>""")
for row in toplevel:
format(row)
print("""
</p>
</body>
</html>
""")
view.py
#!/usr/bin/python
print('Content-type: text/html\n')
import cgitb; cgitb.enable()
"""
根据传入的ID在数据库查询信息以html方式显示内容此条内容的信息
跳转的链接,跳转到回复编辑的界面
"""
import pymysql
ip = '127.0.0.1'
db = 'billbord'
user = 'root'
port = 3308
passwrd = 'PSPS2053'
conn = pymysql.connect(host =ip,db = db,user = user,port = port,passwd=passwrd)
curs = conn.cursor(cursor=pymysql.cursors.DictCursor) #设置返回内容为字典的形式
import cgi, sys
form = cgi.FieldStorage()
id = form.getvalue('id') #获取cgi传递的参数
print("""
<html>
<head>
<title>View Message</title>
</head>
<body>
<h1>View Message</h1>
""")
try: id = int(id)
except:
print('Invalid message ID')
sys.exit()
curs.execute('SELECT * FROM message WHERE id = %s', (format(id),))
rows = curs.fetchall()
if not rows:
print('Unknown message ID')
sys.exit()
row = rows[0]
print("""
<p><b>Subject:</b> {subject}<br />
<b>Sender:</b> {sender}<br />
<pre>{text}</pre>
</p>
<hr />
<a href='main.py'>Back to the main page</a> <!--返回主页的方式-->
| <a href="edit.py?reply_to={id}">Reply</a> <!--跳转到编辑界面的链接-->
</body>
</html>
""".format(subject=row['subject'],sender=row['sender'],text=row['text'],id=row['id']))
edit.py
#!/usr/bin/python
print('Content-type: text/html\n')
import cgitb; cgitb.enable()
import pymysql
ip = '127.0.0.1'
db = 'billbord'
user = 'root'
port = 3308
passwrd = 'PSPS2053'
conn = pymysql.connect(host =ip,db = db,user = user,port = port,passwd=passwrd)
curs = conn.cursor(cursor=pymysql.cursors.DictCursor) #设置返回内容为字典的形式
"""
实现了回复功能;接收传递过来的id,作为replay_to编号
"""
import cgi, sys
form = cgi.FieldStorage()
reply_to = form.getvalue('reply_to')
print("""
<html>
<head>
<title>Compose Message</title>
</head>
<body>
<h1>Compose Message</h1>
<form action='save.py' method='POST'> <!--声明使用post方法传递数据,通过表单的形式-->
""")
subject = ''
if reply_to is not None:
print('<input type="hidden" name="reply_to" value="{}"/>'.format(reply_to))
curs.execute('SELECT subject FROM message WHERE id = %s', (format(reply_to),))
subject = curs.fetchone()['subject'] #返回查询到的subject的主题
if not subject.startswith('Re: '):
subject = 'Re: ' + subject
"""
以html的格式展示回复数据;包括回复主题;回复人;回复内容
提供保存链接
"""
print("""
<b>Subject:</b><br />
<input type='text' size='40' name='subject' value='{}' /><br /> <!--br为html的换行元素-->
<b>Sender:</b><br />
<input type='text' size='40' name='sender' /><br />
<b>Message:</b><br />
<textarea name='text' cols='40' rows='20'></textarea><br />
<input type='submit' value='Save'/>
</form>
<hr />
<a href='main.py'>Back to the main page</a>
</body>
</html>
""".format(subject))
save.py
#!/usr/bin/python
print('Content-type: text/html\n')
import cgitb; cgitb.enable()
import pymysql
ip = '127.0.0.1'
db = 'billbord'
user = 'root'
port = 3308
passwrd = 'PSPS2053'
conn = pymysql.connect(host =ip,db = db,user = user,port = port,passwd=passwrd)
curs = conn.cursor(cursor=pymysql.cursors.DictCursor) #设置返回内容为字典的形式
"""
实现了数据保存
通过cgi传递过来的数据:reply_to,sender,text,subject数据插入数据库;
"""
import cgi, sys
form = cgi.FieldStorage()
sender = form.getvalue('sender')
subject = form.getvalue('subject')
text = form.getvalue('text')
reply_to = form.getvalue('reply_to')
if not (sender and subject and text):
print('Please supply sender, subject, and text')
sys.exit()
if reply_to is not None:
query = ("""INSERT INTO message(reply_to, sender, subject, text) VALUES(%s, %s, %s, %s)""",
(int(reply_to), sender, subject, text))
else:
query = ("""INSERT INTO message(sender, subject, text) VALUES(%s, %s, %s)""", (sender, subject, text))
curs.execute(*query)
conn.commit()
print("""
<html>
<head>
<title>Message Saved</title>
</head>
<body>
<h1>Message Saved</h1>
<hr />
<a href='main.py'>Back to the main page</a>
</body>
</html>s
""")