Add docs to the src
[frozenviper.git] / docs / google-appengine-docs-20100817 / appengine / articles / djangoforms.html
blobd7378ae5c940feac9309a41d98d00a2e3a965219
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
31 <html>
32 <head>
33 <script type="text/javascript" language="JavaScript">
34 ORIGINAL_PAGE_PATH = "/appengine/articles/djangoforms.html";
35 </script>
38 <meta http-equiv="content-type" content="text/html; charset=utf-8">
39 <title>The Django Form Validation Framework on Google App Engine - Google App Engine - Google Code</title>
40 <script type="text/javascript"><!--
41 (function(){function a(){this.t={};this.tick=function(c){this.t[c]=(new Date).getTime()};this.tick("start")}var b=new a;window.jstiming={Timer:a,load:b};if(window.external&&window.external.pageT)window.jstiming.pt=window.external.pageT;})();
43 var _tocPath_ = '/appengine/docs/_toc.ezt';
44 var codesite_token = null;
45 var logged_in_user_email = null;
46 //--></script>
47 <link href="../../css/codesite.pack.04102009.css" type="text/css" rel="stylesheet">
48 <script src="../../js/codesite_head.pack.04102009.js" type="text/javascript"></script>
49 <script type="text/javascript">CODESITE_CSITimer['load'].tick('bhs');</script>
50 <link rel="search" type="application/opensearchdescription+xml" title="Google Code" href="http://code.google.com/osd.xml">
52 <!--[if IE]><link rel="stylesheet" type="text/css" href="../../css/iehacks.css"><![endif]-->
54 <link href="../../css/semantic_headers.css" rel="stylesheet" type="text/css" />
55 <link href="../css/local_extensions.css" rel="stylesheet" type="text/css" />
56 <script src="../js/customtabs.js" type="text/javascript"></script>
57 <script src="../js/ui.tabs.js" type="text/javascript"></script>
58 </head>
60 <body class="gc-documentation">
64 <div id="gb">
65 <span>
67 <a id="lang-dropdown" class="dropdown" href="http://code.google.com" onclick="return false;"><img width="13" height="13" class="globeicon" src="../../images/globe2_small.png"
68 ><span style="text-decoration:underline">English</span> <span style="font-size:.75em;">&#9660;</span></a>
70 </span>
71 </div>
73 <div class="gbh" style="left:0px;"></div>
74 <div class="gbh" style="right:0px;"></div>
76 <div id="gc-container">
77 <a id="top"></a>
78 <div id="skipto">
79 <a href="#gc-pagecontent-anchor">Skip to page content</a>
80 <a href="#gc-toc-anchor">Skip to main navigation</a>
81 </div>
83 <div id="gc-header">
84 <div id="logo"><a href="http://code.google.com">
87 <img src="../../images/code_logo.png" height="40" width="161" alt="Google Code" style="border:0;margin:3px 0 0 0;">
90 </a></div>
91 <div id="search">
92 <div id="searchForm" class="searchForm">
93 <form id="cse" action="http://www.google.com/cse" accept-charset="utf-8" class="gsc-search-box" onsubmit="executeGSearch(document.getElementById('gsearchInput').value); return false;">
94 <noscript>
95 <input type="hidden" name="cref" value="http://code.google.com/cse/googlecode-context.xml">
96 </noscript>
97 <div id="gsc-search-box">
98 <input id="gsearchInput" type="text" name="q" maxlength="2048" class="gsc-input" autocomplete="off" title="Google Code Search" style="width:345px">
99 <div id="cs-searchresults" onclick="event.cancelBubble = true;"></div>
100 <input title="Search" id="gsearchButton" class="gsc-search-button" name="sa" value="Search" type="submit">
101 <div class="greytext">e.g. "templates" or "datastore"</div>
102 </div>
103 </form>
104 </div> <!-- end searchForm -->
105 </div> <!-- end search -->
110 </div> <!-- end gc-header -->
113 <div id="codesiteContent">
115 <a id="gc-topnav-anchor"></a>
116 <div id="gc-topnav">
117 <h1 style="padding:0 0 0 6px;">Google App Engine</h1>
118 <ul id="articles" class="gc-topnav-tabs">
120 <li id="home_link">
121 <a href="../index.html" title="Google App Engine home page">Home</a>
122 </li>
124 <li id="docs_link">
125 <a href="../docs/index.html" title="Official Google App Engine documentation">Docs</a>
126 </li>
128 <li id="faq_link">
129 <a href="../kb/index.html" title="Answers to frequently asked questions about Google App Engine">FAQ</a>
130 </li>
132 <li id="articles_link">
133 <a href="index.html" class="selected" title="Focused articles and tutorials for Google App Engine developers">Articles</a>
134 </li>
136 <li>
137 <a href="http://googleappengine.blogspot.com/" title="Official Google App Engine blog">Blog</a>
138 </li>
140 <li>
141 <a href="../community.html" title="Community home for Google App Engine">Community</a>
142 </li>
144 <li>
145 <a href="../terms.html" title="Google App Engine terms of service">Terms</a>
146 </li>
148 <li>
149 <a href="../downloads.html" title="Download Google App Engine">Download</a>
150 </li>
153 </ul>
154 </div> <!-- end gc-topnav -->
156 <div class="g-section g-tpl-170">
158 <a name="gc-toc-anchor"></a>
159 <div class="g-unit g-first" id="gc-toc">
160 <ul>
161 <li><a href="../downloads.html">Downloads</a></li>
162 <li><a href="http://code.google.com/status/appengine">System Status</a></li>
163 <li><a href="http://code.google.com/p/googleappengine/issues/list">Issue Tracker</a></li>
164 <li><a href="../business/index.html">App Engine for Business</a> <sup class="new">New!</sup></li>
165 </ul>
166 <div class="line"></div>
167 <ul>
168 <li><h2>Getting Started</h2>
169 <ul>
170 <li><a href="../docs/whatisgoogleappengine.html">What Is Google App Engine?</a></li>
171 <li><a href="../docs/java/gettingstarted/index.html">Java</a>
172 <ul>
173 <li><a href="../docs/java/gettingstarted/introduction.html">Introduction</a></li>
174 <li><a href="../docs/java/gettingstarted/installing.html">Installing the Java SDK</a></li>
175 <li><a href="../docs/java/gettingstarted/creating.html">Creating a Project</a></li>
176 <li><a href="../docs/java/gettingstarted/usingusers.html">Using the Users Service</a></li>
177 <li><a href="../docs/java/gettingstarted/usingjsps.html">Using JSPs</a></li>
178 <li><a href="../docs/java/gettingstarted/usingdatastore.html">Using the Datastore with JDO</a></li>
179 <li><a href="../docs/java/gettingstarted/staticfiles.html">Using Static Files</a></li>
180 <li><a href="../docs/java/gettingstarted/uploading.html">Uploading Your Application</a></li>
182 </ul>
183 </li>
184 <li><a href="../docs/python/gettingstarted/index.html">Python</a>
185 <ul>
186 <li><a href="../docs/python/gettingstarted/introduction.html">Introduction</a></li>
187 <li><a href="../docs/python/gettingstarted/devenvironment.html">The Development Environment</a></li>
188 <li><a href="../docs/python/gettingstarted/helloworld.html">Hello, World!</a></li>
189 <li><a href="../docs/python/gettingstarted/usingwebapp.html">Using the webapp Framework</a></li>
190 <li><a href="../docs/python/gettingstarted/usingusers.html">Using the Users Service</a></li>
191 <li><a href="../docs/python/gettingstarted/handlingforms.html">Handling Forms With webapp</a></li>
192 <li><a href="../docs/python/gettingstarted/usingdatastore.html">Using the Datastore</a></li>
193 <li><a href="../docs/python/gettingstarted/templates.html">Using Templates</a></li>
194 <li><a href="../docs/python/gettingstarted/staticfiles.html">Using Static Files</a></li>
195 <li><a href="../docs/python/gettingstarted/uploading.html">Uploading Your Application</a></li>
197 </ul>
198 </li>
199 </ul>
200 </li>
201 </ul>
202 <div class="line"></div>
203 <ul>
204 <li><h2>Java</h2>
205 <ul>
206 <li><a href="../docs/java/overview.html">Overview</a></li>
207 <li><a href="../docs/java/runtime.html">Servlet Environment</a></li>
208 <li><a href="../docs/java/datastore/index.html">Storing Data</a>
209 <ul>
210 <li><a href="../docs/java/datastore/overview.html">Overview</a></li>
211 <li><a href="../docs/java/datastore/usingjdo.html">Using JDO</a></li>
212 <li><a href="../docs/java/datastore/dataclasses.html">Defining Data Classes</a></li>
213 <li><a href="../docs/java/datastore/creatinggettinganddeletingdata.html">Creating, Getting and Deleting Data</a></li>
214 <li><a href="../docs/java/datastore/queriesandindexes.html">Queries and Indexes</a></li>
215 <li><a href="../docs/java/datastore/transactions.html">Transactions</a></li>
216 <li><a href="../docs/java/datastore/relationships.html">Relationships</a></li>
217 <li><a href="../docs/java/datastore/stats.html">Statistics</a></li>
218 <li><a href="../docs/java/datastore/usingjpa.html">Using JPA</a></li>
219 <li><a href="../docs/java/javadoc/com/google/appengine/api/datastore/package-summary.html">Low-level API</a></li>
221 </ul>
222 </li>
223 <li><a href="../docs/java/apis.html">Services</a>
224 <ul>
225 <li><a href="../docs/java/blobstore/index.html">Blobstore</a>
226 <ul>
227 <li><a href="../docs/java/blobstore/overview.html">Overview</a></li>
228 <li><span class="tlw-title tlw-expanded">Reference</span>
229 <ul>
230 <li><a href="../docs/java/javadoc/com/google/appengine/api/blobstore/package-summary.html">API Reference</a></li>
231 </ul>
232 </li>
234 </ul>
235 </li>
236 <li><a href="../docs/java/images/index.html">Images</a>
237 <ul>
238 <li><a href="../docs/java/images/overview.html">Overview</a></li>
239 <li><a href="../docs/java/javadoc/com/google/appengine/api/images/package-summary.html">API Reference</a></li>
241 </ul>
242 </li>
243 <li><a href="../docs/java/mail/index.html">Mail</a>
244 <ul>
245 <li><a href="../docs/java/mail/overview.html">Overview</a></li>
246 <li><a href="../docs/java/mail/usingjavamail.html">Using JavaMail to Send Mail</a></li>
247 <li><a href="../docs/java/mail/receiving.html">Receiving Mail</a></li>
248 <li><a href="../docs/java/javadoc/com/google/appengine/api/mail/package-summary.html">Low-level API</a></li>
250 </ul>
251 </li>
252 <li><a href="../docs/java/memcache/index.html">Memcache</a>
253 <ul>
254 <li><a href="../docs/java/memcache/overview.html">Overview</a></li>
255 <li><a href="../docs/java/memcache/usingjcache.html">Using JCache</a></li>
256 <li><a href="../docs/java/javadoc/com/google/appengine/api/memcache/package-summary.html">Low-level API</a></li>
258 </ul>
259 </li>
260 <li><a href="../docs/java/multitenancy/index.html">Multitenancy</a>
261 <ul>
262 <li><a href="../docs/java/multitenancy/overview.html">Overview</a></li>
263 <li><a href="../docs/java/multitenancy/multitenancy.html">Multitenancy with Namespaces</a></li>
264 <li><a href="../docs/java/multitenancy/namespaces.html">Other Uses for Namespaces</a></li>
265 <li><a href="../docs/java/javadoc/com/google/appengine/api/NamespaceManager.html">API Reference</a>
267 </ul>
268 </li>
269 <li><a href="../docs/java/oauth/index.html">OAuth</a>
270 <ul>
271 <li><a href="../docs/java/oauth/overview.html">Overview</a></li>
272 <li><a href="../docs/java/javadoc/com/google/appengine/api/oauth/package-summary.html">API Reference</a></li>
275 </ul>
276 </li>
277 <li><a href="../docs/java/taskqueue/index.html">Task Queues</a>
278 <ul>
279 <li><a href="../docs/java/taskqueue/overview.html">Overview</a></li>
280 <li><a href="../docs/java/javadoc/com/google/appengine/api/labs/taskqueue/package-summary.html">API Reference</a></li>
282 </ul>
283 </li>
284 <li><a href="../docs/java/urlfetch/index.html">URL Fetch</a>
285 <ul>
286 <li><a href="../docs/java/urlfetch/overview.html">Overview</a></li>
287 <li><a href="../docs/java/urlfetch/usingjavanet.html">Using java.net</a></li>
288 <li><a href="../docs/java/javadoc/com/google/appengine/api/urlfetch/package-summary.html">Low-level API</a></li>
290 </ul>
291 </li>
292 <li><a href="../docs/java/users/index.html">Users</a>
293 <ul>
294 <li><a href="../docs/java/users/overview.html">Overview</a></li>
295 <li><a href="../docs/java/javadoc/com/google/appengine/api/users/package-summary.html">API Reference</a></li>
297 </ul>
298 </li>
299 <li><a href="../docs/java/xmpp/index.html">XMPP</a>
300 <ul>
301 <li><a href="../docs/java/xmpp/overview.html">Overview</a></li>
302 <li><a href="../docs/java/javadoc/com/google/appengine/api/xmpp/package-summary.html">API Reference</a></li>
304 </ul>
305 </li>
306 </ul>
307 </li>
308 <li><a href="../docs/java/javadoc/index.html">Services Javadoc</a></li>
309 <li><a href="../docs/java/jrewhitelist.html">JRE Class White List</a></li>
310 <li><a href="../docs/java/config/index.html">Configuration</a>
311 <ul>
312 <li><a href="../docs/java/config/webxml.html">Deployment Descriptor</a></li>
313 <li><a href="../docs/java/config/appconfig.html">App Config</a></li>
314 <li><a href="../docs/java/config/indexconfig.html">Index Config</a></li>
315 <li><a href="../docs/java/config/cron.html">Scheduled Tasks</a></li>
316 <li><a href="../docs/java/config/queue.html">Task Queue Config</a></li>
317 <li><a href="../docs/java/config/dos.html">DoS Protection Config</a></li>
319 </ul>
320 </li>
321 <li><a href="../docs/java/configyaml/index.html">YAML Configuration</a>
322 <ul>
323 <li><a href="../docs/java/configyaml/appconfig_yaml.html">YAML App Config</a></li>
324 <li><a href="../docs/java/configyaml/indexconfig.html">Index Config</a></li>
325 <li><a href="../docs/java/configyaml/cron.html">Scheduled Tasks</a></li>
326 <li><a href="../docs/java/configyaml/queue.html">Task Queue Config</a></li>
327 <li><a href="../docs/java/configyaml/dos.html">DoS Protection Config</a></li>
329 </ul>
330 </li>
331 <li><a href="../docs/java/tools/index.html">Tools</a>
332 <ul>
333 <li><a href="../docs/java/tools/devserver.html">Development Server</a></li>
334 <li><a href="../docs/java/tools/uploadinganapp.html">Uploading and Managing</a></li>
335 <li><a href="../docs/java/tools/eclipse.html">Google Plugin for Eclipse</a></li>
336 <li><a href="../docs/java/tools/ant.html">Using Apache Ant</a></li>
337 <li><a href="../docs/java/tools/localunittesting.html">Local Unit Testing</a>
338 <ul>
339 <li><a href="../docs/java/tools/localunittesting/javadoc/index.html">Testing Javadoc</a></li>
340 </ul>
341 </li>
342 <li><a href="../docs/java/tools/appstats.html">Appstats</a></li>
344 </ul>
345 </li>
346 <li><a href="../docs/java/howto/index.html">How-To</a>
347 <ul>
348 <li><a href="../docs/java/howto/maintenance.html">Handling Scheduled Maintenance Periods</a></li>
350 </ul>
351 </li>
353 </ul>
354 </li>
355 </ul>
356 <div class="line"></div>
357 <ul>
358 <li><h2>Python</h2>
359 <ul>
360 <li><a href="../docs/python/overview.html">Overview</a></li>
361 <li><a href="../docs/python/runtime.html">CGI Environment</a></li>
362 <li><a href="../docs/python/datastore/index.html">Storing Data</a>
363 <ul>
364 <li><a href="../docs/python/datastore/overview.html">Overview</a></li>
365 <li><a href="../docs/python/datastore/entitiesandmodels.html">Entities and Models</a></li>
366 <li><a href="../docs/python/datastore/creatinggettinganddeletingdata.html">Creating, Getting and Deleting Data</a></li>
367 <li><a href="../docs/python/datastore/keysandentitygroups.html">Keys and Entity Groups</a></li>
368 <li><a href="../docs/python/datastore/queriesandindexes.html">Queries and Indexes</a></li>
369 <li><a href="../docs/python/datastore/transactions.html">Transactions</a></li>
370 <li><a href="../docs/python/datastore/typesandpropertyclasses.html">Types and Property Classes</a></li>
371 <li><a href="../docs/python/datastore/gqlreference.html">GQL Reference</a></li>
372 <li><a href="../docs/python/datastore/stats.html">Statistics</a></li>
374 <li><span class="tlw-title tlw-expanded">Reference</span>
375 <ul>
376 <li><a href="../docs/python/datastore/modelclass.html">Model</a></li>
377 <li><a href="../docs/python/datastore/expandoclass.html">Expando</a></li>
378 <li><a href="../docs/python/datastore/polymodelclass.html">PolyModel</a></li>
379 <li><a href="../docs/python/datastore/propertyclass.html">Property</a></li>
380 <li><a href="../docs/python/datastore/queryclass.html">Query</a></li>
381 <li><a href="../docs/python/datastore/gqlqueryclass.html">GqlQuery</a></li>
382 <li><a href="../docs/python/datastore/keyclass.html">Key</a></li>
383 <li><a href="../docs/python/datastore/functions.html">Functions</a></li>
384 <li><a href="../docs/python/datastore/exceptions.html">Exceptions</a></li>
385 </ul>
386 </li>
388 </ul>
389 </li>
390 <li><a href="../docs/python/apis.html">Services</a>
391 <ul>
392 <li><a href="../docs/python/blobstore/index.html">Blobstore</a>
393 <ul>
394 <li><a href="../docs/python/blobstore/overview.html">Overview</a></li>
395 <li><span class="tlw-title tlw-expanded">Reference</span>
396 <ul>
397 <li><a href="../docs/python/blobstore/blobinfoclass.html">BlobInfo</a></li>
398 <li><a href="../docs/python/blobstore/blobkeyclass.html">BlobKey</a></li>
399 <li><a href="../docs/python/blobstore/blobreaderclass.html">BlobReader</a></li>
400 <li><a href="../docs/python/blobstore/functions.html">Functions</a></li>
401 <li><a href="../docs/python/blobstore/exceptions.html">Exceptions</a></li>
402 </ul>
403 </li>
405 </ul>
406 </li>
407 <li><a href="../docs/python/images/index.html">Images</a>
408 <ul>
409 <li><a href="../docs/python/images/overview.html">Overview</a></li>
410 <li><a href="../docs/python/images/installingPIL.html">Installing PIL</a></li>
411 <li><a href="../docs/python/images/usingimages.html">Using the Images API</a></li>
412 <li><span class="tlw-title tlw-expanded">Reference</span>
413 <ul>
414 <li><a href="../docs/python/images/imageclass.html">Image</a></li>
415 <li><a href="../docs/python/images/functions.html">Functions</a></li>
416 <li><a href="../docs/python/images/exceptions.html">Exceptions</a></li>
417 </ul>
418 </li>
420 </ul>
421 </li>
422 <li><a href="../docs/python/mail/index.html">Mail</a>
423 <ul>
424 <li><a href="../docs/python/mail/overview.html">Overview</a></li>
425 <li><a href="../docs/python/mail/sendingmail.html">Sending Mail</a></li>
426 <li><a href="../docs/python/mail/receivingmail.html">Receiving Mail</a></li>
427 <li><a href="../docs/python/mail/attachments.html">Attachments</a></li>
428 <li><span class="tlw-title tlw-expanded">Reference</span>
429 <ul>
430 <li><a href="../docs/python/mail/emailmessageclass.html">EmailMessage</a></li>
431 <li><a href="../docs/python/mail/emailmessagefields.html">Message Fields</a></li>
432 <li><a href="../docs/python/mail/functions.html">Functions</a></li>
433 <li><a href="../docs/python/mail/exceptions.html">Exceptions</a></li>
434 </ul>
435 </li>
437 </ul>
438 </li>
439 <li><a href="../docs/python/memcache/index.html">Memcache</a>
440 <ul>
441 <li><a href="../docs/python/memcache/overview.html">Overview</a></li>
442 <li><a href="../docs/python/memcache/usingmemcache.html">Using Memcache</a></li>
443 <li><span class="tlw-title tlw-expanded">Reference</span>
444 <ul>
445 <li><a href="../docs/python/memcache/clientclass.html">Client</a></li>
446 <li><a href="../docs/python/memcache/functions.html">Functions</a></li>
447 </ul>
448 </li>
450 </ul>
451 </li>
452 <li><a href="../docs/python/multitenancy/index.html">Multitenancy</a>
453 <ul>
454 <li><a href="../docs/python/multitenancy/overview.html">Overview</a></li>
455 <li><a href="../docs/python/multitenancy/multitenancy.html">Multitenancy with Namespaces</a></li>
456 <li><a href="../docs/python/multitenancy/namespaces.html">Other Uses for Namespaces</a></li>
457 <li>Reference
458 <ul>
459 <li><a href="../docs/python/multitenancy/functions.html">Functions</a></li>
460 <li><a href="../docs/python/multitenancy/exceptions.html">Exceptions</a></li>
461 </ul>
462 </li>
464 </ul>
465 </li>
466 <li><a href="../docs/python/oauth/index.html">OAuth</a>
467 <ul>
468 <li><a href="../docs/python/oauth/overview.html">Overview</a></li>
469 <li><span class="tlw-title tlw-expanded">Reference</span>
470 <ul>
471 <li><a href="../docs/python/oauth/functions.html">Functions</a></li>
472 <li><a href="../docs/python/oauth/exceptions.html">Exceptions</a></li>
473 </ul>
474 </li>
476 </ul>
477 </li>
478 <li><a href="../docs/python/taskqueue/index.html">Task Queues</a>
479 <ul>
480 <li><a href="../docs/python/taskqueue/overview.html">Overview</a></li>
481 <li><span class="tlw-title tlw-expanded">Reference</span>
482 <ul>
483 <li><a href="../docs/python/taskqueue/tasks.html">Task Class</a></li>
484 <li><a href="../docs/python/taskqueue/queues.html">Queue Class</a></li>
485 <li><a href="../docs/python/taskqueue/functions.html">Functions</a></li>
486 <li><a href="../docs/python/taskqueue/exceptions.html">Exceptions</a></li>
487 </ul>
488 </li>
490 </ul>
491 </li>
492 <li><a href="../docs/python/urlfetch/index.html">URL Fetch</a>
493 <ul>
494 <li><a href="../docs/python/urlfetch/overview.html">Overview</a></li>
495 <li><span class="tlw-title tlw-expanded">Reference</span>
496 <ul>
497 <li><a href="../docs/python/urlfetch/fetchfunction.html">The fetch Function</a></li>
498 <li><a href="../docs/python/urlfetch/asynchronousrequests.html">Asynchronous Requests</a></li>
499 <li><a href="../docs/python/urlfetch/responseobjects.html">Response Objects</a></li>
500 <li><a href="../docs/python/urlfetch/exceptions.html">Exceptions</a></li>
501 </ul>
502 </li>
504 </ul>
505 </li>
506 <li><a href="../docs/python/users/index.html">Users</a>
507 <ul>
508 <li><a href="../docs/python/users/overview.html">Overview</a></li>
509 <li><a href="../docs/python/users/userobjects.html">User Objects</a></li>
510 <li><a href="../docs/python/users/loginurls.html">Login URLs</a></li>
511 <li><a href="../docs/python/users/adminusers.html">Admin Users</a></li>
513 <li><span class="tlw-title tlw-expanded">Reference</span>
514 <ul>
515 <li><a href="../docs/python/users/userclass.html">User</a></li>
516 <li><a href="../docs/python/users/functions.html">Functions</a></li>
517 <li><a href="../docs/python/users/exceptions.html">Exceptions</a></li>
518 </ul>
519 </li>
521 </ul>
522 </li>
523 <li><a href="../docs/python/xmpp/index.html">XMPP</a>
524 <ul>
525 <li><a href="../docs/python/xmpp/overview.html">Overview</a></li>
526 <li><span class="tlw-title tlw-expanded">Reference</span>
527 <ul>
528 <li><a href="../docs/python/xmpp/functions.html">Functions</a></li>
529 <li><a href="../docs/python/xmpp/messageclass.html">Message</a></li>
530 <li><a href="../docs/python/xmpp/exceptions.html">Exceptions</a></li>
531 </ul>
532 </li>
534 </ul>
535 </li>
536 </ul>
537 </li>
538 <li><a href="../docs/python/config/index.html">Configuration</a>
539 <ul>
540 <li><a href="../docs/python/config/appconfig.html">App Config</a></li>
541 <li><a href="../docs/python/config/indexconfig.html">Index Config</a></li>
542 <li><a href="../docs/python/config/cron.html">Scheduled Tasks</a></li>
543 <li><a href="../docs/python/config/queue.html">Task Queue Config</a></li>
544 <li><a href="../docs/python/config/dos.html">DoS Protection Config</a></li>
546 </ul>
547 </li>
548 <li><a href="../docs/python/tools/index.html">Tools</a>
549 <ul>
550 <li><a href="../docs/python/tools/devserver.html">Development Server</a></li>
551 <li><a href="../docs/python/tools/uploadinganapp.html">Uploading and Managing</a></li>
552 <li><a href="../docs/python/tools/uploadingdata.html">Uploading and Downloading Data</a></li>
553 <li><a href="../docs/python/tools/webapp/index.html">webapp Framework</a>
554 <ul>
555 <li><a href="../docs/python/tools/webapp/overview.html">Overview</a></li>
556 <li><a href="../docs/python/tools/webapp/running.html">Running the Application</a></li>
557 <li><a href="../docs/python/tools/webapp/requesthandlers.html">Request Handlers</a></li>
558 <li><a href="../docs/python/tools/webapp/requestdata.html">Request Data</a></li>
559 <li><a href="../docs/python/tools/webapp/buildingtheresponse.html">Building the Response</a></li>
560 <li><a href="../docs/python/tools/webapp/redirects.html">Redirects, Headers and Status Codes</a></li>
561 <li><a href="../docs/python/tools/webapp/blobstorehandlers.html">Blobstore Handlers</a></li>
563 <li><span class="tlw-title tlw-expanded">Reference</span>
564 <ul>
565 <li><a href="../docs/python/tools/webapp/requestclass.html">Request</a></li>
566 <li><a href="../docs/python/tools/webapp/responseclass.html">Response</a></li>
567 <li><a href="../docs/python/tools/webapp/requesthandlerclass.html">RequestHandler</a></li>
568 <li><a href="../docs/python/tools/webapp/wsgiapplicationclass.html">WSGIApplication</a></li>
569 <li><a href="../docs/python/tools/webapp/utilmodule.html">Utility Functions</a></li>
571 </ul>
572 </li>
574 </ul>
575 </li>
576 <li><a href="../docs/python/tools/appstats.html">Appstats</a></li>
577 <li><a href="../docs/python/tools/libraries.html">Third-party Libraries</a></li>
579 </ul>
580 </li>
581 <li><a href="../docs/python/howto/index.html">How-To</a>
582 <ul>
583 <li><a href="../docs/python/howto/usinggdataservices.html">Google Data Services</a></li>
584 <li><a href="../docs/python/howto/maintenance.html">Handling Scheduled Maintenance Periods</a></li>
586 </ul>
587 </li>
589 </ul>
590 </li>
591 </ul>
592 <div class="line"></div>
593 <ul>
594 <li><h2>Managing Your App</h2>
595 <ul>
596 <li><a href="../docs/theadminconsole.html">The Admin Console</a></li>
597 <li><a href="../docs/quotas.html">Quotas</a></li>
598 <li><a href="../docs/billing.html">Billing</a></li>
599 <li><a href="../docs/domain.html">Using a Custom Domain</a></li>
600 </ul>
601 </li>
602 </ul>
603 <div class="line"></div>
604 <ul>
605 <li><h2>Resources</h2>
606 <ul>
607 <li><a href="../kb/index.html">FAQ</a></li>
608 <li><a href="index.html">Articles</a></li>
609 <li><a href="http://appengine-cookbook.appspot.com/">Cookbook</a></li>
610 <li><a href="http://appgallery.appspot.com/">App Gallery</a></li>
611 <li><a href="http://code.google.com/p/googleappengine/">SDK Code</a></li>
612 <li><a href="http://code.google.com/p/datanucleus-appengine/">JDO/JPA Code</a></li>
613 <li><a href="http://code.google.com/p/google-app-engine-samples/">Sample Apps Code</a></li>
614 <li>Launcher Code
615 <ul>
616 <li><a href="http://code.google.com/p/google-appengine-mac-launcher/">Mac</a></li>
617 <li><a href="http://code.google.com/p/google-appengine-wx-launcher/">Windows/wx</a></li>
618 </ul>
619 </li>
620 <li><a href="../community.html">Discussion Groups</a></li>
621 </ul>
622 </li>
623 </ul>
624 <div class="line"></div>
625 <ul>
626 <li><a href="../docs/roadmap.html">Product Roadmap</a></li>
627 <li><a href="http://code.google.com/p/googleappengine/wiki/SdkReleaseNotes">Release Notes: Python</a></li>
628 <li><a href="http://code.google.com/p/googleappengine/wiki/SdkForJavaReleaseNotes">Release Notes: Java</a></li>
629 <li><a href="../docs/revision_history.html">Revision History</a></li>
630 </ul>
632 <a class="hidden" href="#gc-topnav-anchor">More Google App Engine resource links</a>
633 </div>
635 <a name="gc-pagecontent-anchor"></a>
636 <div class="g-unit" id="gc-pagecontent">
637 <script type="text/javascript">CODESITE_docEarlyProcessing();</script>
638 <h1 class="page_title">The Django Form Validation Framework on Google App Engine</h1>
641 <i>Alexander Power</i><br>
642 <i>April 2008</i>
644 <div id="jd-content">
645 <div class="jd-descr">
647 <h2>Introduction</h2>
648 <p>In this article we show how to use Django's form validation framework with the Google App Engine. This framework allows you to construct HTML forms from your data models, and handle the inputted information from the forms seamlessly when interacting with the datastore.</p>
650 <h2>What is the Django Form Validation Framework?</h2>
652 Django's form validation framework is included with the Django project. It uses a database model to construct well formed HTML forms for your application. It also handles the server-side functionality to validate the entry and put the data entered in to your datastore. With the Django forms framework, you can easily turn your data model into a set of pages that can be used to insert and update data in a datastore. Once the data is in the datastore, you can use GQL queries to access this data.</p>
654 <h2>How do Django Forms Interact with the Datastore?</h2>
655 <p>The Google App Engine <a href="../docs/python/datastore/modelclass.html">model class</a>, <code>db.Model</code>, is not the same as the model class used by Django. As a result, you cannot directly use the Django forms framework with Google App Engine. However, Google App Engine includes a module, db.djangoforms, which casts between the datastore models used with Google App Engine and the Django models specification. In most cases, you can use db.djangoforms.ModelForm in the same manner as the Django framework.</p>
657 <h2>Shopping List - An Example</h2>
658 <p>We are going to develop a simple application uses Django forms which creates pages that allow you to add and edit items on a shopping list, then stores the information in our datastore. Finally we will use <a href="../docs/python/datastore/gqlreference.html">GQL</a> to query the data and display it in our application.</p>
659 <p>First, we specify the Python module imports and Google App Engine imports for our application. <b>Please note that you must import <code>google.appengine.webapp.template</code> before importing any Django modules:</b></p>
660 <pre class="prettyprint">import cgi
662 from google.appengine.api import users
663 from google.appengine.ext import db
664 from google.appengine.ext import webapp
665 from google.appengine.ext.webapp import template
666 from google.appengine.ext.webapp.util import run_wsgi_app
668 from google.appengine.ext.db import djangoforms
669 </pre>
671 <h2>Define Model and Form Classes for our Example</h2>
672 <p>Next, we define our model for a shopping list entry as a subclass of the Google App Engine <code>db.Model</code> class. For each object, we note the name of the item, how many we want, what price we want to pay, the date we made the entry, and by whom it was made:</p>
673 <pre class="prettyprint">class Item(db.Model):
674 name = db.StringProperty()
675 quantity = db.IntegerProperty(default=1)
676 target_price = db.FloatProperty()
677 priority = db.StringProperty(default='Medium',choices=[
678 'High', 'Medium', 'Low'])
679 entry_time = db.DateTimeProperty(auto_now_add=True)
680 added_by = db.UserProperty()
681 </pre>
682 <p>Next, we create the form object based on the model. To do this, we create a class that inherits from <code>djangofroms.ModelForm</code>, and create a subclass of that class called <code>Meta</code> in which we specify the model and any excluded fields that we do not need in our form. In this case, since we will utilize the Users API to get the person who added the item to the shopping list, we will not need to include the added_by field on our form:</p>
683 <pre class="prettyprint">class ItemForm(djangoforms.ModelForm):
684 class Meta:
685 model = Item
686 exclude = ['added_by']
687 </pre>
688 <p>We also don't need to have the user specify the entrytime. However, DateTime fields with auto_now or auto_now_add set to true are automatically not displayed when a form is generated. Therefore, we do not need to include the entry_time field in the list for exclusions.</p>
690 <h2>Defining Request Handlers </h2>
691 <h3>Adding an Item</h3>
692 <p>Now, let us create the request handlers for our shopping list. The form will be accessed at the root URL via HTTP GET, and the user will submit it to our application via an HTTP POST to the same URL.</p>
693 <p>One of the advantages of Django forms is the automatic form validation. If the user submitted data is invalid, it will produce an error and automatically display form messaging that will ask the user to fix their input errors.</p>
694 <p>To define the HTTP GET request method:</p>
695 <pre class="prettyprint">class MainPage(webapp.RequestHandler):
696 def get(self):
697 self.response.out.write('&lt;html&gt;&lt;body&gt;'
698 '&lt;form method="POST" '
699 'action="/"&gt;'
700 '&lt;table&gt;')
701 # This generates our shopping list form and writes it in the response
702 self.response.out.write(ItemForm())
703 self.response.out.write('&lt;/table&gt;'
704 '&lt;input type="submit"&gt;'
705 '&lt;/form>&lt;/body>&lt;/html&gt;')
706 </pre>
707 <p>The form will pre-populate the entries with default values where they are provided, and will otherwise leave blanks. Additionally, if a fixed list of choices are provided, a drop-down menu will be created.</p>
708 <p>Next, we write a method to handle the HTTP POST request:</p>
709 <pre class="prettyprint"> def post(self):
710 data = ItemForm(data=self.request.POST)
711 if data.is_valid():
712 # Save the data, and redirect to the view page
713 entity = data.save(commit=False)
714 entity.added_by = users.get_current_user()
715 entity.put()
716 self.redirect('/items.html')
717 else:
718 # Reprint the form
719 self.response.out.write('&lt;html&gt;&lt;body&gt;'
720 '&lt;form method="POST" '
721 'action="/"&gt;'
722 '&lt;table&gt;')
723 self.response.out.write(data)
724 self.response.out.write('&lt;/table&gt;'
725 '&lt;input type="submit"&gt;'
726 '&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;')
727 </pre>
728 <p>We use <code>data.is_valid()</code> to check that there are no errors in the user input. If errors are found, the form is reprinted with the user entered information and appropriate error messages.</p>
729 <p>If the form input is valid, data.save will generate the datastore entity. Since we wish to add the user information to the entity, we specify <code>commit=False</code>. Without this flag, calling save() would save the entity directly to the datastore. We include the current user information, and then call the <code>put()</code> method to save the data to our datastore.</p>
731 <p class="note">Default values are very effective ways to initialize entities in your datastore. However, we cannot use this to initialize the current user with <code>users.get_current_user()</code>, because the value is cached between requests. The <a href="../docs/python/datastore/propertyclass.html">Property</a> page has more information.</p>
733 <h3>Displaying our List</h3>
734 <p>After we have added items to our shopping list, we want to display them to the user when he requests the URL <code>/items.html</code>. We create another request handler for this page that queries the datastore using the GQL query language.</p>
735 <pre class="prettyprint">class ItemPage(webapp.RequestHandler):
736 def get(self):
737 query = db.GqlQuery("SELECT * FROM Item ORDER BY name")
738 for item in query:
739 self.response.out.write("%s - Need to buy %d, cost $%0.2f each&lt;br&gt;" %
740 (item.name, item.quantity, item.target_price))
741 </pre>
743 <h2>Writing our <code>main()</code> Function</h2>
744 <p>After writing all our handler classes, we need to define the <code>main()</code> function for this program to handle the CGI requests:</p>
745 <pre class="prettyprint">def main():
746 application = webapp.WSGIApplication(
747 [('/', MainPage),
748 ('/items.html', ItemPage),
750 debug=True)
751 run_wsgi_app(application)
753 if __name__=="__main__":
754 main()
755 </pre>
756 <p>This main function directs each request to the appropriate handler class based on the URL request.</p>
758 <h2>Writing our <code>app.yaml</code> File</h2>
759 <p>With Google App Engine, the <a href="../docs/python/config/appconfig.html">app.yaml</a> file contains the specification as to which script will handle an incoming request. Our application only has one script, form.py, so all requests will be handled by that script:</p>
760 <pre class="prettyprint">application: shoppinglist
761 version: 1
762 runtime: python
763 api_version: 1
765 handlers:
766 - url: .*
767 script: form.py
768 </pre>
770 <h2> Editing Existing Entities</h2>
771 <p>We can extend the above example by allowing the users of our shopping list to edit an existing shopping list entry.</p>
772 <h3>Modifying our <code>ItemPage</code> Class</h3>
773 <p>First, when handling the item page request, we'll add a link next to each item that they can click on to edit the entry. The link will request the <code>/edit</code> URL, and include the item id as a query argument.</p>
774 <pre class="prettyprint">class ItemPage(webapp.RequestHandler):
775 def get(self):
776 query = db.GqlQuery("SELECT * FROM Item ORDER BY name")
777 for item in query:
778 self.response.out.write('&lt;a href="/edit?id=%d">Edit&lt;/a&gt; - ' %
779 item.key().id())
780 self.response.out.write("%s - Need to buy %d, cost $%0.2f each&lt;br&gt;" %
781 (item.name, item.quantity, item.target_price))
782 </pre>
784 <h3>Adding an <code>EditPage</code> Class</h3>
785 <p>Now we must add the <code>EditPage</code> class to handle the edit request. This handler is similar to handlers used to add an item.</p>
786 <p>In the <code>get()</code> method, for our EditPage class, we first retrieve the instance we are editing from the datastore, and then pass that instance to form renderer so that the item information can be populated. Also, we add the item id as a hidden input to the form so that we can access the id information when the user submits the edited item:</p>
787 <pre class="prettyprint">class EditPage(webapp.RequestHandler):
788 def get(self):
789 <b> id = int(self.request.get('id'))
790 item = Item.get(db.Key.from_path('Item', id))</b>
791 self.response.out.write('&lt;html&gt;&lt;body&gt;'
792 '&lt;form method="POST" '
793 <b> 'action="/edit"&gt;'</b>
794 '&lt;table&gt;')
795 self.response.out.write(ItemForm(instance=item))
796 self.response.out.write('&lt;/table>'
797 <b> '&lt;input type="hidden" name="_id" value="%s"&gt;'</b>
798 '&lt;input type="submit"&gt;'
799 '&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;' % id)
800 </pre>
801 <p>Next we write the method to handle the HTTP POST. We query our datastore for the item we are editing, and then validate the edited information using the validation framework available with Django forms. As before, if the information is valid, we put the change in the datastore, or else we allow the user to modify their input:</p>
802 <pre class="prettyprint"> def post(self):
803 <b> id = int(self.request.get('_id'))
804 item = Item.get(db.Key.from_path('Item', id))</b>
805 data = ItemForm(data=self.request.POST, instance=item)
806 if data.is_valid():
807 # Save the data, and redirect to the view page
808 entity = data.save(commit=False)
809 entity.added_by = users.get_current_user()
810 entity.put()
811 self.redirect('/items.html')
812 else:
813 # Reprint the form
814 self.response.out.write('&lt;html&gt;&lt;body&gt;'
815 '&lt;form method="POST" '
816 <b> 'action="/edit"&gt;'</b>
817 '&lt;table&gt;')
818 self.response.out.write(data)
819 self.response.out.write('&lt;/table&gt;'
820 <b> '&lt;input type="hidden" name="_id" value="%s"&gt;'</b>
821 '&lt;input type="submit"&gt;'
822 '&lt;/form&gt;&lt;/body&gt;&lt;/html&gt;' % id)
823 </pre>
825 <h3>Modifying your <code>main()</code> Function</h3>
826 <p>Lastly, we must add the new URL and request handler to our main function:</p>
827 <pre class="prettyprint">def main():
828 application = webapp.WSGIApplication(
829 [('/', MainPage),
830 <b> ('/edit', EditPage),</b>
831 ('/items.html', ItemPage),
833 debug=True)
835 run_wsgi_app(application)
836 </pre>
838 <h2>Additional Notes on Setting Up Django Forms</h2>
839 <p>Django's form validating framework does strict validation against data types. However, it does not provide Javascript validation on the client side of input. As a result, some data types, such as dates and lists, may be more difficult to use with Django forms, because users must enter the data in the specific format required.</p>
842 </div>
843 </div>
847 </div><!-- end gc-pagecontent -->
848 </div><!-- end gooey wrapper -->
850 </div> <!-- end codesite content -->
853 <div id="gc-footer" dir="ltr">
854 <div class="text">
856 <div class="notice"><div id="notice" style="text-align: center; border: 1em 0em 1em 0em">
857 Except as otherwise <a
858 href="http://code.google.com/policies.html#restrictions">noted</a>,
859 the content of this page is licensed under the <a rel="license"
860 href="http://creativecommons.org/licenses/by/3.0/">Creative Commons
861 Attribution 3.0 License</a>, and code samples are licensed under the
862 <a rel="license" href="http://www.apache.org/licenses/LICENSE-2.0">Apache
863 2.0 License</a>.
864 <!-- <rdf:RDF xmlns="http://web.resource.org/cc/"
865 xmlns:dc="http://purl.org/dc/elements/1.1/"
866 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
867 <Work rdf:about="">
868 <license rdf:resource="http://creativecommons.org/licenses/by/3.0/" />
869 </Work>
870 <License rdf:about="http://creativecommons.org/licenses/by/3.0/">
871 <permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
872 <permits rdf:resource="http://web.resource.org/cc/Distribution"/>
873 <requires rdf:resource="http://web.resource.org/cc/Notice"/>
874 <requires rdf:resource="http://web.resource.org/cc/Attribution"/>
875 <permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
876 </License>
877 </rdf:RDF> -->
878 </div>
879 Java is a registered trademark of Sun Microsystems, Inc.</div>
881 &copy;2010 Google -
882 <a href="http://code.google.com">Code Home</a> -
883 <a href="http://code.google.com/terms.html">Terms of Service</a> -
884 <a href="http://code.google.com/privacy.html">Privacy Policy</a> -
885 <a href="http://code.google.com/more">Site Directory</a>
886 <br> <br>
887 Google Code offered in:
888 <a href="http://code.google.com/intl/en">English</a> -
889 <a href="http://code.google.com/intl/es">Español</a> -
890 <a href="http://code.google.com/intl/ja">日本語</a> -
891 <a href="http://code.google.com/intl/ko">한국어</a> -
892 <a href="http://code.google.com/intl/pt-BR">Português</a> -
893 <a href="http://code.google.com/intl/ru">Pусский</a> -
894 <a href="http://code.google.com/intl/zh-CN">中文(简体)</a> -
895 <a href="http://code.google.com/intl/zh-TW">中文(繁體)</a>
896 </div>
897 </div><!-- end gc-footer -->
899 </div><!-- end gc-container -->
901 <script type="text/javascript">CODESITE_CSITimer['load'].tick('ats');</script>
902 <script src="../../js/codesite_tail.pack.04102009.js" type="text/javascript"></script>
907 <script type="text/javascript">
908 var _gaq = _gaq || [];
910 _gaq.push(
913 ['siteTracker._setAccount', 'UA-18071-1'],
914 ['siteTracker._setDomainName', 'code.google.com'],
915 ['siteTracker._setCookiePath', window.location.pathname.substring(0,
916 window.location.pathname.lastIndexOf('/') + 1)],
917 ['siteTracker._trackPageview']
919 (function() {
920 var ga = document.createElement('script');
922 ga.type = 'text/javascript';
923 ga.async = true;
924 ga.src = 'http://www.google-analytics.com/ga.js';
925 (document.getElementsByTagName('head')[0] ||
926 document.getElementsByTagName('body')[0]).appendChild(ga);
927 })();
928 </script>
933 </body>
934 </html>