Beginning Python - From Novice to Professional
Beginning Python - From Novice to Professional Beginning Python - From Novice to Professional
CHAPTER 26 ■ PROJECT 7: YOUR OWN BULLETIN BOARD 485 In addition, because you want to be able to display the messages hierarchically (threading), each message should store a reference to the message it is a reply to. The resulting CREATE TABLE SQL command is shown in Listing 26-1. Listing 26-1. Creating the Database in PostgreSQL CREATE TABLE messages ( id SERIAL PRIMARY KEY, subject TEXT NOT NULL, sender TEXT NOT NULL, reply_to INTEGER REFERENCES messages, text TEXT NOT NULL ); Note that this command uses some PostgreSQL-specific features (serial, which ensures that each message automatically receives a unique ID, the text data type, and references, which makes sure that reply_to contains a valid message ID). A more MySQL-friendly version is shown in Listing 26-2. Listing 26-2. Creating the Database in MySQL 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) ); I’ve kept these code snippets simple (an SQL guru would certainly find ways to improve them) because the focus of this chapter is, after all, the Python code. The SQL statements create a new table with the following five fields (columns): id: Used to identify the individual messages. Each message automatically receives a unique id by the database manager, so you don’t have to worry about assigning those from your Python code. subject: A string that contains the subject of the message. sender: A string that contains the sender’s name or e-mail address or something like that. reply_to: If the message is a reply to another message, this field contains the id of the other message. (Otherwise, the field won’t contain anything.) text: A string that contains the body of the message. When you’ve created this database and set the permissions on it so that your Web server is allowed to read its contents and insert new rows, you’re ready to start coding the CGI.
486 CHAPTER 26 ■ PROJECT 7: YOUR OWN BULLETIN BOARD First Implementation In this project, the first prototype will be very limited. It will be a single script that uses the database functionality so that you can get a feel for how it works. Once you’ve got that pegged, writing the other necessary scripts won’t be very hard. In many ways, this is just a short reminder of the material covered in Chapter 13. The CGI part of the code is very similar to that in Chapter 25. If you haven’t read that chapter yet, you might want to take a look at it. You should also be sure to review the section “CGI Security Risks” in Chapter 15. ■Caution In the CGI scripts in this chapter, I’ve imported and enabled the cgitb module. This is very useful to uncover flaws in your code, but you should probably remove the call to cgitb.enable before deploying the software—you probably wouldn’t want an ordinary user to face a full cgitb traceback. The first thing you need to know is how the DB API works. If you haven’t read Chapter 13, you probably should at least skim through it now. If you’d rather just press on, here is the core functionality again (replace db with the name of your database module—for example, psycopg or MySQLdb): conn = db.connect('user=foo dbname=bar'): Connects to the database named bar as user foo and assigns the returned connection object to conn. (Note that the parameter to connect is a string.) ■Caution In this project, I assume that you have a dedicated machine on which the database and Web server run. The given user (foo) should only be allowed to connect from that machine to avoid unwanted access. If you have other users on your machine, you should probably protect your database with a password, which may also be supplied in the parameter string to connect. To find out more about this, you should consult the documentation for your database (and your Python database module). curs = conn.cursor(): Gets a cursor object from the connection object. The cursor is used to actually execute SQL statements and fetch the results. conn.commit(): Commits the changes caused by the SQL statements since the last commit. conn.close(): Closes the connection. curs.execute(sql_string): Executes an SQL statement. curs.fetchone(): Fetches one result row as a sequence—for example, a tuple. curs.dictfetchone(): Fetches one result row as a dictionary. (Not part of the standard, and therefore not available in all modules.) curs.fetchall(): Fetches all result rows as a sequence of sequences—for example, a list of tuples.
- Page 466 and 467: CHAPTER 22 ■ PROJECT 3: XML FOR A
- Page 468: CHAPTER 22 ■ PROJECT 3: XML FOR A
- Page 471 and 472: 440 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 473 and 474: 442 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 475 and 476: 444 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 477 and 478: 446 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 479 and 480: 448 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 481 and 482: 450 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 483 and 484: 452 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 486 and 487: CHAPTER 24 ■ ■ ■ Project 5: A
- Page 488 and 489: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 490 and 491: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 492 and 493: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 494 and 495: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 496 and 497: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 498 and 499: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 500 and 501: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 502 and 503: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 504 and 505: CHAPTER 25 ■ ■ ■ Project 6: R
- Page 506 and 507: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 508 and 509: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 510 and 511: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 512: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 515: 484 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 519 and 520: 488 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 521 and 522: 490 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 523 and 524: 492 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 525 and 526: 494 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 527 and 528: 496 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 529 and 530: 498 CHAPTER 26 ■ PROJECT 7: YOUR
- Page 531 and 532: 500 CHAPTER 27 ■ PROJECT 8: FILE
- Page 533 and 534: 502 CHAPTER 27 ■ PROJECT 8: FILE
- Page 535 and 536: 504 CHAPTER 27 ■ PROJECT 8: FILE
- Page 537 and 538: 506 CHAPTER 27 ■ PROJECT 8: FILE
- Page 539 and 540: 508 CHAPTER 27 ■ PROJECT 8: FILE
- Page 541 and 542: 510 CHAPTER 27 ■ PROJECT 8: FILE
- Page 543 and 544: 512 CHAPTER 27 ■ PROJECT 8: FILE
- Page 545 and 546: 514 CHAPTER 27 ■ PROJECT 8: FILE
- Page 547 and 548: 516 CHAPTER 27 ■ PROJECT 8: FILE
- Page 549 and 550: 518 CHAPTER 28 ■ PROJECT 9: FILE
- Page 551 and 552: 520 CHAPTER 28 ■ PROJECT 9: FILE
- Page 553 and 554: 522 CHAPTER 28 ■ PROJECT 9: FILE
- Page 555 and 556: 524 CHAPTER 28 ■ PROJECT 9: FILE
- Page 558 and 559: CHAPTER 29 ■ ■ ■ Project 10:
- Page 560 and 561: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 562 and 563: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
- Page 564 and 565: CHAPTER 29 ■ PROJECT 10: DO-IT-YO
CHAPTER 26 ■ PROJECT 7: YOUR OWN BULLETIN BOARD 485<br />
In addition, because you want <strong>to</strong> be able <strong>to</strong> display the messages hierarchically (threading),<br />
each message should s<strong>to</strong>re a reference <strong>to</strong> the message it is a reply <strong>to</strong>. The resulting CREATE TABLE<br />
SQL command is shown in Listing 26-1.<br />
Listing 26-1. Creating the Database in PostgreSQL<br />
CREATE TABLE messages (<br />
id SERIAL PRIMARY KEY,<br />
subject TEXT NOT NULL,<br />
sender TEXT NOT NULL,<br />
reply_<strong>to</strong> INTEGER REFERENCES messages,<br />
text TEXT NOT NULL<br />
);<br />
Note that this command uses some PostgreSQL-specific features (serial, which ensures<br />
that each message au<strong>to</strong>matically receives a unique ID, the text data type, and references,<br />
which makes sure that reply_<strong>to</strong> contains a valid message ID). A more MySQL-friendly version<br />
is shown in Listing 26-2.<br />
Listing 26-2. Creating the Database in MySQL<br />
CREATE TABLE messages (<br />
id INT NOT NULL AUTO_INCREMENT,<br />
subject VARCHAR(100) NOT NULL,<br />
sender VARCHAR(15) NOT NULL,<br />
reply_<strong>to</strong> INT,<br />
text MEDIUMTEXT NOT NULL,<br />
PRIMARY KEY(id)<br />
);<br />
I’ve kept these code snippets simple (an SQL guru would certainly find ways <strong>to</strong> improve<br />
them) because the focus of this chapter is, after all, the <strong>Python</strong> code. The SQL statements create<br />
a new table with the following five fields (columns):<br />
id: Used <strong>to</strong> identify the individual messages. Each message au<strong>to</strong>matically receives a unique<br />
id by the database manager, so you don’t have <strong>to</strong> worry about assigning those from your<br />
<strong>Python</strong> code.<br />
subject: A string that contains the subject of the message.<br />
sender: A string that contains the sender’s name or e-mail address or something like that.<br />
reply_<strong>to</strong>: If the message is a reply <strong>to</strong> another message, this field contains the id of the<br />
other message. (Otherwise, the field won’t contain anything.)<br />
text: A string that contains the body of the message.<br />
When you’ve created this database and set the permissions on it so that your Web server is<br />
allowed <strong>to</strong> read its contents and insert new rows, you’re ready <strong>to</strong> start coding the CGI.