Add docs to the src
[frozenviper.git] / docs / google-appengine-docs-20100817 / appengine / articles / modeling.html
blob160ddc43e77d94e010d02eac70f8ebda49250ca6
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/modeling.html";
35 </script>
38 <meta http-equiv="content-type" content="text/html; charset=utf-8">
39 <title>Modeling Entity Relationships - 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">Modeling Entity Relationships</h1>
641 <i>Rafe Kaplan, Software Engineer</i><br>
642 <i>June 2008</i>
644 <div id="jd-content">
645 <div class="jd-descr">
647 <p class="note" align="center">This is one of a <a href="datastore/overview.html">series</a> of in-depth articles discussing App Engine's datastore. To see the other articles in the series, see <a href="#related">Related links</a>.</p>
649 <p>Sure, the Getting Started Guide tells you what you need to know in order to fill properties for a simple AppEngine model, but it's going to take more than that if you want to be able to represent real world concepts in the datastore. Whether you are new to web application development, or are used to working with SQL databases, this article is for those people who are ready to take a step into the next dimension of AppEngine data representation.</p>
650 <h2>Why would I need entity relationships?</h2>
651 <p>Imagine you are building a snazzy new web application that includes an address book where users can store their contacts. For each contact the user stores, you want to capture the contacts name, birthday (which they mustn't forget!) their address, telephone number and company they work for.</p>
652 <p>When the user wants to add an address, they enter the information in to a form and the form saves the information in a model that looks something like this:</p>
653 <pre class="prettyprint">class Contact(db.Model):
655 # Basic info.
656 name = db.StringProperty()
657 birth_day = db.DateProperty()
659 # Address info.
660 address = db.PostalAddressProperty()
662 # Phone info.
663 phone_number = db.PhoneNumberProperty()
665 # Company info.
666 company_title = db.StringProperty()
667 company_name = db.StringProperty()
668 company_description = db.StringProperty()
669 company_address = db.PostalAddressProperty()
670 </pre>
671 <p>That's great, your users immediately begin to use their address book and soon the datastore starts to fill up. Not long after the deployment of your new application you hear from someone that they are not happy that there is only one phone number. What if they want to storesomeone's work telephone number in addition to their home number? No problem you think, you can just add a work phone number to your structure. You change your data structure to look more like this:</p>
672 <pre class="prettyprint"> # Phone info.
673 phone_number = db.PhoneNumberProperty()
674 work_phone_number = db.PhoneNumberProperty()
675 </pre>
676 <p>Update the form with the new field and you are back in business. Soon after redeploying your application, you get a number of new complaints. When they see the new phone number field, people start asking for even more fields. Some people want a fax number field, others want a mobile field. Some people even want more than one mobile field (boy modern life sure is hectic)! You could add another field for fax, and another for mobile, maybe two. What about if people have three mobile phones? What if they have ten? What if someone invents a phone for a place you've never thought of?</p>
677 <p>Your model needs to use relationships.</p>
678 <h2>One to Many</h2>
679 <p>The answer is to allow users to assign as many phone numbers to each of their contacts as they like. To do this, you need to model the phone numbers in their own class and have a way of associating many phone numbers to a single Contact. You can easily model the one to many relationship using ReferenceProperty. Here is a candidate for this new class:</p>
680 <pre class="prettyprint">class Contact(db.Model):
682 # Basic info.
683 name = db.StringProperty()
684 birth_day = db.DateProperty()
686 # Address info.
687 address = db.PostalAddressProperty()
689 <b> # The original phone_number property has been replaced by
690 # an implicitly created property called 'phone_numbers'.</b>
692 # Company info.
693 company_title = db.StringProperty()
694 company_name = db.StringProperty()
695 company_description = db.StringProperty()
696 company_address = db.PostalAddressProperty()
698 <b>class PhoneNumber(db.Model):
699 contact = db.ReferenceProperty(Contact,
700 collection_name='phone_numbers')
701 phone_type = db.StringProperty(
702 choices=('home', 'work', 'fax', 'mobile', 'other'))
703 number = db.PhoneNumberProperty()</b>
704 </pre>
705 <p>The key to making all this work is the <code>contact</code> property. By defining it as a <code>ReferenceProperty</code>, you have created a property that can only be assigned values of type Contact. Every time you define a reference property, it creates an implicit collection property on the referenced class. By default, this collection is called <code><i>&lt;name-of-class&gt;</i>_set</code>. In this case, it would make a property <code>Contact.phonenumber_set</code>. However, it is probably more intuitive to call that attribute <code>phone_numbers</code>. You over-rode this default name using the <code>collection_name</code> keyword parameter to <code>ReferenceProperty</code>.</p>
706 <p>Creating the relationship between a contact and one of its phone numbers is easy to do. Let's say you have a contact named "Scott" who has a home phone and a mobile phone. You populate his contact info like this:</p>
707 <pre class="prettyprint">scott = Contact(name='Scott')
708 scott.put()
709 PhoneNumber(contact=scott,
710 phone_type='home',
711 number='(650) 555 - 2200').put()
712 PhoneNumber(contact=scott,
713 phone_type='mobile',
714 number='(650) 555 - 2201').put()
715 </pre>
716 <p>Because <code>ReferenceProperty</code> creates this special property on <code>Contact</code>, it makes it very easy to retrieve all the phone numbers for a given person. If you wanted to print all the phone numbers for a given person, you can do it like this:</p>
717 <pre class="prettyprint">print 'Content-Type: text/html'
718 print
719 for phone in scott.phone_numbers:
720 print '%s: %s' % (phone.phone_type, phone.number)
721 </pre>
722 <p>This will produce results that look like:</p>
723 <pre>home: (650) 555 - 2200
724 mobile: (650) 555 - 2201
725 </pre>
726 <p class="note"><b>Note:</b> The order of the output might be different as by default there is no ordering in this kind of relationship.</p>
727 <p>The <code>phone_numbers</code> virtual attribute is a <code>Query</code> instance, meaning that you can use it to further narrow down and sort the collection associated with the <code>Contact</code>. For example, if you only want to get the home phone numbers, you can do this:</p>
728 <pre class="prettyprint">scott.phone_numbers.filter('phone_type =', 'home')</pre>
729 <p>When Scott loses his phone, it's easy enough to delete that record. Just delete the PhoneNumber instance and it can no longer be queried for:</p>
730 <pre class="prettyprint">scott.phone_numbers.filter('phone_type =', 'home').get().delete()</pre>
731 <h2>Many to Many</h2>
732 <p>One thing you would like to do is provide the ability for people to organize their contacts in to groups. They might make groups like "Friends", "Co-workers" and "Family". This would allow users to use these groups to perform actions en masse, such as maybe sending an invitation to all their friends for a hack-a-thon. Let's define a simple <code>Group</code> model like this:</p>
733 <pre class="prettyprint">class Group(db.Model):
735 name = db.StringProperty()
736 description = db.TextProperty()
737 </pre>
738 <p>You could make a new <code>ReferenceProperty</code> on <code>Contact</code> called group. However, this would allow contacts to be part of only one group at a time. For example, someone might include some of their co-workers as friends. You need a way to represent many-to-many relationships.</p>
739 <h3>List of Keys</h3>
740 <p>One very simple way is to create a list of keys on one side of the relationship:</p>
741 <pre class="prettyprint"> class Contact(db.Model):
742 # User that owns this entry.
743 owner = db.UserProperty()
745 # Basic info.
746 name = db.StringProperty()
747 birth_day = db.DateProperty()
749 # Address info.
750 address = db.PostalAddressProperty()
752 # Company info.
753 company_title = db.StringProperty()
754 company_name = db.StringProperty()
755 company_description = db.StringProperty()
756 company_address = db.PostalAddressProperty()
758 <b> # Group affiliation
759 groups = db.ListProperty(db.Key)</b>
760 </pre>
761 <p>Adding and removing a user to and from a group means working with a list of keys:</p>
762 <pre class="prettyprint">friends = Group.gql("WHERE name = 'friends'").get()
763 mary = Contact.gql("WHERE name = 'Mary'").get()
764 if friends.key() not in mary.groups:
765 mary.groups.append(friends.key())
766 mary.put()
767 </pre>
768 <p>To get all the members of a group, you can execute a simple query. It might help to add a helper function to the <code>Group</code> entity:</p>
769 <pre class="prettyprint">class Group(db.Model):
770 name = db.StringProperty()
771 description = db.TextProperty()
773 <b> @property
774 def members(self):
775 return Contact.gql("WHERE groups = :1", self.key())</b>
776 </pre>
777 <p>There are a few limitations to implementing many-to-many relationships this way. First, you must explicitly retrieve the values on the side of the collection where the list is stored since all you have available are <code>Key</code> objects. Another more important one is that you want to avoid storing overly large lists of keys in a <code>ListProperty</code>. This means you should place the list on side of the relationship which you expect to have fewer values. In the example above, the <code>Contact</code> side was chosen because a single person is not likely to belong to too many groups, whereas in a large contacts database, a group might contain hundreds of members.</p>
778 <h2>Relationship Model</h2>
779 <p>One of your users is a big time saleswoman and knows teams of people in just one company. She is finding it very tedious to have to enter the same information about the same company again and again. Couldn't there be a way to specify a company once and then associate them with each person? If it were that simple, it would merely be necessary to have a one-to-many relationship between <code>Contact</code> and <code>Company</code>, but it's more complicated than that. Some of her contacts are contractors that work at more than one company and have different titles in each. What now?</p>
780 <p>You need a many-to-many relationship that can describe some additional information about that relationship. To accomplish this, you can use another <code>Model</code> to describe the relationship:</p>
781 <pre class="prettyprint">class Contact(db.Model):
782 # User that owns this entry.
783 owner = db.UserProperty()
785 # Basic info.
786 name = db.StringProperty()
787 birth_day = db.DateProperty()
789 # Address info.
790 address = db.PostalAddressProperty()
792 <b> # The original organization properties have been replaced by
793 # an implicitly created property called 'companies'. </b>
795 # Group affiliation
796 groups = db.ListProperty(db.Key)
798 <b>class Company(db.Model):
799 name = db.StringProperty()
800 description = db.StringProperty()
801 company_address = db.PostalAddressProperty()
803 class ContactCompany(db.Model):
804 contact = db.ReferenceProperty(Contact,
805 required=True,
806 collection_name='companies')
807 company = db.ReferenceProperty(Company,
808 required=True,
809 collection_name='contacts')
810 title = db.StringProperty()</b>
811 </pre>
812 <p>Adding someone to a company is done by creating a <code>ContactCompany</code> instance:</p>
813 <pre class="prettyprint">mary = Contact.gql("name = 'Mary'").get()
814 google = Company.gql("name = 'Google'").get()
815 ContactCompany(contact=mary,
816 company=google,
817 title='Engineer').put()</pre>
818 <p>In addition to being able to being able to store information about a relationship, using this method has the advantage over the list-of-keys method in that you can have large collections on either side of the relationship. However, you need to be very careful because traversing the connections of a collection will require more calls to the datastore. Use this kind of many-to-many relationship only when you really need to, and do so with care to the performance of your application.</p>
819 <h2>Conclusion</h2>
820 <p>App Engine allows the creation of easy to use relationships between datastore entities which can represent real-world things and ideas. Use <code>ReferenceProperty</code> when you need to associate an arbitrary number of repeated types of information with a single entity. Use key-lists when you need to allow lots of different objects to share other instances between each other. You will find that these two approaches will provide you with most of what you need to create the model behind great applications.</p>
822 <h2 id="related">Related links</h2>
824 <ul>
825 <li><a href="datastore/overview.html">Series Overview</a></li>
826 <li><a href="life_of_write.html">Life of a Datastore Write</a></li>
827 <li><a href="transaction_isolation.html">Transaction Isolation in App Engine</a></li>
828 <li><a href="index_building.html">How Index Building Works</a></li>
829 <li><a href="storage_breakdown.html">How Entities and Indexes are Stored</a></li>
830 <li><a href="modeling.html">Modeling Entity Relationships</a></li>
831 <li><a href="update_schema.html">Updating Your Model's Schema</a></li>
832 <li><a href="handling_datastore_errors.html">Handling Datastore Errors</a></li>
833 </ul>
836 </div>
837 </div>
841 </div><!-- end gc-pagecontent -->
842 </div><!-- end gooey wrapper -->
844 </div> <!-- end codesite content -->
847 <div id="gc-footer" dir="ltr">
848 <div class="text">
850 <div class="notice"><div id="notice" style="text-align: center; border: 1em 0em 1em 0em">
851 Except as otherwise <a
852 href="http://code.google.com/policies.html#restrictions">noted</a>,
853 the content of this page is licensed under the <a rel="license"
854 href="http://creativecommons.org/licenses/by/3.0/">Creative Commons
855 Attribution 3.0 License</a>, and code samples are licensed under the
856 <a rel="license" href="http://www.apache.org/licenses/LICENSE-2.0">Apache
857 2.0 License</a>.
858 <!-- <rdf:RDF xmlns="http://web.resource.org/cc/"
859 xmlns:dc="http://purl.org/dc/elements/1.1/"
860 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
861 <Work rdf:about="">
862 <license rdf:resource="http://creativecommons.org/licenses/by/3.0/" />
863 </Work>
864 <License rdf:about="http://creativecommons.org/licenses/by/3.0/">
865 <permits rdf:resource="http://web.resource.org/cc/Reproduction"/>
866 <permits rdf:resource="http://web.resource.org/cc/Distribution"/>
867 <requires rdf:resource="http://web.resource.org/cc/Notice"/>
868 <requires rdf:resource="http://web.resource.org/cc/Attribution"/>
869 <permits rdf:resource="http://web.resource.org/cc/DerivativeWorks"/>
870 </License>
871 </rdf:RDF> -->
872 </div>
873 Java is a registered trademark of Sun Microsystems, Inc.</div>
875 &copy;2010 Google -
876 <a href="http://code.google.com">Code Home</a> -
877 <a href="http://code.google.com/terms.html">Terms of Service</a> -
878 <a href="http://code.google.com/privacy.html">Privacy Policy</a> -
879 <a href="http://code.google.com/more">Site Directory</a>
880 <br> <br>
881 Google Code offered in:
882 <a href="http://code.google.com/intl/en">English</a> -
883 <a href="http://code.google.com/intl/es">Español</a> -
884 <a href="http://code.google.com/intl/ja">日本語</a> -
885 <a href="http://code.google.com/intl/ko">한국어</a> -
886 <a href="http://code.google.com/intl/pt-BR">Português</a> -
887 <a href="http://code.google.com/intl/ru">Pусский</a> -
888 <a href="http://code.google.com/intl/zh-CN">中文(简体)</a> -
889 <a href="http://code.google.com/intl/zh-TW">中文(繁體)</a>
890 </div>
891 </div><!-- end gc-footer -->
893 </div><!-- end gc-container -->
895 <script type="text/javascript">CODESITE_CSITimer['load'].tick('ats');</script>
896 <script src="../../js/codesite_tail.pack.04102009.js" type="text/javascript"></script>
901 <script type="text/javascript">
902 var _gaq = _gaq || [];
904 _gaq.push(
907 ['siteTracker._setAccount', 'UA-18071-1'],
908 ['siteTracker._setDomainName', 'code.google.com'],
909 ['siteTracker._setCookiePath', window.location.pathname.substring(0,
910 window.location.pathname.lastIndexOf('/') + 1)],
911 ['siteTracker._trackPageview']
913 (function() {
914 var ga = document.createElement('script');
916 ga.type = 'text/javascript';
917 ga.async = true;
918 ga.src = 'http://www.google-analytics.com/ga.js';
919 (document.getElementsByTagName('head')[0] ||
920 document.getElementsByTagName('body')[0]).appendChild(ga);
921 })();
922 </script>
927 </body>
928 </html>