公告板,我理解的是不是门岗大爷旁边的那个,通知我们最近需要我们注意的事情,我想除了检查卫生没别的了,而且好久也不见更新,还有一个就是电子公告板,流水字那个,就是很多二极管组成的数码管来显示字的那种(而且需要流动的),当然这个项目不是这个,公告板就是显示信息来通知别人的,那么这些信息是存储在那的呢?进入公告标题,里面应该是其内容或者还有一些其他的信息,这篇是把信息存在数据库里。
先看看数据库中建的一个表吧:
create table messages(
id int not null auto_increment,
subject varchar(100) not null,
sender varchar(15) not null,
reply_to int,
text mediumtext not null,
primary key(id));
如代码所示,只是建了 id ,subject,sender,reply_to,text,等5个字段和各自的类型及
最大字符串长度。其中主键是id.
作为一个公告板,一定能显示信息和编辑信息吧。
先看看公告板的主页代码,所有通知的信息都应该在主页显示,不然该去哪看。
print 'Content-type:text/html\n'
print
#import cgitb:cgitb.enable()
import MySQLdb
conn = MySQLdb.connect(db='hu',user='root')
curs = conn.cursor()
print '''
<html>
<head>
<title>The hu yiyang</title>
</head>
<body>
<h1>The hu yiyang </h1>
'''
curs.execute('SELECT * FROM messages')
rows = curs.fetchall()
toplevel = []
children = {}
for row in rows:
parent_id = row[3]
if parent_id is None:
toplevel.append(row)
else:
children.setdefault(parent_id,[]).append(row)
def format(row):
print '<p><a href="view.cgi?id=%i">%s<a>' %
(row[0],row[1])
try:
kids = children[row[0]]
except KeyError:
pass
else:
print '<blockquote>'
for kid in kids:
format(kid)
print '</blockquote>'
print '<p>'
for row in toplevel:
format(row)
print '''
</p>
<hr/>
<p><a href="edit.cgi">Post Messages</a></p>
</body>
</html>
'''
刚开始与数据库进行连接,‘hu’是数据库名,‘root’是用户名。conn.cursor()是用来获取连接数据库的浮标,用于使用sql语句,下面就是打印一些信息,curs.execute()就是执行里面的sql语句,检索messages表中的所有字段信息,下面的curs.fetchall()就是把检索的信息按序列输出显示,下面这个for是处理有没有回复的消息,如果该主题没有人回复就把该行记录存储 在toplevel列表中,否则就吧该行记录记录到chilren字典中,其中setdefault函数的意思是如果parent_id有值(不是None),也就是有人回复信息,就把该行记录存储在children字典中(当然可以很多人回复消息,所以采用字典来存储),最终就是说没人回复的主题放在toplevel中,有人回复的放在children中。接着是format函数,主要进行对每一条记录显示的问题, print '<p><a href="view.cgi?id=%i">%s<a>' % (row[0],row[1])的意思就是只要你点击某个主题,就会连接到其对应的内容里,然后又是捕捉异常的了,如果children[row['0']]有值,也就是说有回复信息,就会在该主题里显示出该回复信息,否则会引发一个KeyError异常,不过这个异常的执行是pass.,对应没人回复的信息也会执行一次format来链接显示这个主题。最后还有一个链接是Post me
ssages,用于链接到编辑页面,edit.cgi.
下面看edit.cgi代码:
print 'Content-type: text/html\n'
#import cgitb: cgitb.enable()
import MySQLdb
conn = MySQLdb.connect(db='hu',user='root')
curs = conn.cursor()
import cgi,sys
form = cgi.FieldStorage()
reply_to = form.getvalue('reply_to')
print """
<html>
<head>
<title>Compose Messages</title>
</head>
<body>
<h1>Compose Messages</h1>
<form action='/cgi-bin/save.cgi' method='POST'>
"""
subject = ''
if reply_to is not None:
print '<input type="hidden" name="reply_to"
value="%s"/>'% reply_to
curs.execute('SELECT subject FROM messages WHERE
id=%s'% reply_to)
subject = curs.fetchone()[0]
if not subject.startswith('Re: '):
subject = 'Re: '+subject
print '''
<b>Subject:</b><br/>
<input type='text' size='40' name='subject'
value='%s' /><br/>
<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.cgi'>back to the main page</a>
</body>
</html>
''' % subject
刚开始都一样,都是链接存储信息的数据库,并且获取连接数据库的游标,以用于使用sql语句。cgi.FieldStorage()在上个项目就有,是用来获取上个页面提交过来的信息(也就是main.cgi),先获取字段名为‘reply_to’的信息(他中存储的是被回复那个主题的ID),存储到reply_to中,下面也是一个打印本页标题的html, <form action='/cgi-bin/save.cgi' method='POST'>就是一个提交表单,要跳转的页面,action的值可以是本站点的url地址,也可以是其他站点的。如果有回复的信息,就把名为‘reply_to’,值为‘ 被回复主题的ID ’的信息隐藏起来(编辑该主题的时候并不需要看该主题的回复情况吧),接着是执行一条sql语句,意思是检索 messages表中id为reply_to的值的主题(就是查找被回复的那个主题),如果主题的开始不为‘Re : ’,则在回复的时候,主题前面自动加上‘Re:’,最后就是html了,各自的标题及文本框,还有个提交按钮‘Save’,用于跳转到save.cgi,还有个链接 back to the main page,用以回到主页。
下面看 save.cgi代码:
print 'Content-type:text/html\n'
import cgitb;cgitb.enable()
def quote(string):
if string:
return string.replace("'","\\'")
else:
return string
import MySQLdb
conn = MySQLdb.connect(db='hu',user='root')
curs = conn.cursor()
import cgi, sys
form = cgi.FieldStorage()
sender = quote(form.getvalue('sender'))
subject = quote(form.getvalue('subject'))
text = quote(form.getvalue('text'))
reply_to = form.getvalue('reply_to')
if not (sender and subject and text):
print 'Please supply sender,subject,text'
sys.exit()
if reply_to is not None:
query = """
INSERT INTO messages
(reply_to,sender,subject,text)
VALUES(%d,'%s','%s','%s')""" % (int
(reply_to),sender,subject,text)
else:
query = """
INSERT INTO messages(sender,subject,text)
VALUES('%s','%s','%s')""" %
(sender,subject,text)
curs.execute(query)
conn.commit()
print '''
<html>
<head>
<title>Messages Saved</title>
</head>
<body>
<h1>Messages Saved</h1>
<hr/>
<a href='main.cgi'>Back to the main page</a>
</body>
</html>s
'''
刚开始就定义一个quote函数,如果字符串存在,就把‘ ‘ ’换成’ \' ‘,否则返回本身。下面都是把获取到的值经过quote函数再赋给一个变量,而字段’reply_to‘就不需要,因为他是个整型,就直接获取了。下面意思是如果sender ,subject,text中有一个不存在(必须三个都存在才可以不执行下面的打印),就会打印需要你输入的信息,然后退出代码。
如果回复不为空,就往messages表中插入一条回复信息的记录,包括(reply_to,sender,subject,text),如果回复为空,就往messages表中插入一条不含有reply_to的记录,就是该条信息没人回复。commit()是把提交给数据库的信息更新。最后还是HTML,一个链接,back to the main page.
最后是 view.cgi:
print 'Content-type:text/html\n'
#import cgitb:cgitb.enable()
import MySQLdb
conn = MySQLdb.connect(db='hu',user='root')
curs = conn.cursor()
import cgi,sys
form = cgi.FieldStorage()
id = form.getvalue('id')
print """
<html>
<head>
<title>View Messages</title>
</head>
<body>
<h1>View Messages</h1>
"""
try:
id = int(id)
except:
print 'Invalid messages ID'
sys.exit()
curs.execute('SELECT * FROM messages WHERE id=%d'%id )
rows = curs.fetchall()
if not rows:
print 'Unknown message ID'
sys.exit()
row = rows[0]
print '''
<p><b>Subject:</b> %s<br/>
<b>Sender:</b>%s<br/>
<pre>%s</pre>
</p>
<hr/>
<a href='main.cgi'>Back to the main page</a>
|<a href="edit.cgi?reply_to=%s">Reply</a>
</body>
</html>
''' % (row[1],row[2],row[4],row[0])
前面一样,不过这个获取上页传来的id的值,主要是用于显示id为某个值的那条记录,一个捕捉id类型的异常。然后是一个数据库查询,查找传过来的那个id的所有记录,如果没有记录则打印未知的id,最后是一个html,比较不同的是这个里面加了个、Reply的链接,用于回复信息跳转到edit.cgi页面。