PageRenderTime 40ms CodeModel.GetById 10ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/DOCS.html

https://bitbucket.org/bconstantin/django_polymorphic/
HTML | 756 lines | 679 code | 77 blank | 0 comment | 0 complexity | 0990bc45a56be8baea30ec657ee48aff MD5 | raw file
  1<?xml version="1.0" encoding="utf-8" ?>
  2<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  4<head>
  5<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  6<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
  7<title></title>
  8<style type="text/css">
  9
 10h1, h2, h3, h4,
 11#table-of-contents
 12{
 13    color: #47c;
 14}
 15h1 { padding-top: 15px; }
 16h2 { padding-top: 10px; }
 17h3 { padding-top: 7px; }
 18
 19a:hover { border-bottom: 1px solid #0066cc; }
 20a {color: #0066cc; text-decoration: none;}
 21
 22li {
 23    padding-top: 5px;
 24    padding-bottom: 5px;
 25}
 26
 27tt {
 28  color: #080;
 29  }
 30
 31blockquote tt {
 32      color: #000
 33}
 34
 35.first {
 36  margin-top: 0 }
 37
 38.last {
 39  margin-bottom: 0 }
 40
 41/*
 42a.toc-backref {
 43  text-decoration: none ;
 44  color: black }
 45*/
 46
 47dd {
 48  margin-bottom: 0.5em }
 49
 50div.abstract {
 51  margin: 2em 5em }
 52
 53div.abstract p.topic-title {
 54  font-weight: bold ;
 55  text-align: center }
 56
 57div.attention, div.caution, div.danger, div.error, div.hint,
 58div.important, div.note, div.tip, div.warning {
 59  margin: 2em ;
 60  border: medium outset ;
 61  padding: 1em }
 62
 63div.attention p.admonition-title, div.caution p.admonition-title,
 64div.danger p.admonition-title, div.error p.admonition-title,
 65div.warning p.admonition-title {
 66  color: red ;
 67  font-weight: bold ;
 68  font-family: sans-serif }
 69
 70div.hint p.admonition-title, div.important p.admonition-title,
 71div.note p.admonition-title, div.tip p.admonition-title {
 72  font-weight: bold ;
 73  font-family: sans-serif }
 74
 75div.dedication {
 76  margin: 2em 5em ;
 77  text-align: center ;
 78  font-style: italic }
 79
 80div.dedication p.topic-title {
 81  font-weight: bold ;
 82  font-style: normal }
 83
 84div.figure {
 85  margin-left: 2em }
 86
 87div.footer, div.header {
 88  font-size: smaller }
 89
 90div.system-messages {
 91  margin: 5em }
 92
 93div.system-messages h1 {
 94  color: red }
 95
 96div.system-message {
 97  border: medium outset ;
 98  padding: 1em }
 99
100div.system-message p.system-message-title {
101  color: red ;
102  font-weight: bold }
103
104div.topic {
105  margin: 2em }
106
107h1.title {
108  text-align: center }
109
110h2.subtitle {
111  text-align: center }
112
113hr {
114  width: 75% }
115
116ol.simple, ul.simple {
117  margin-bottom: 1em }
118
119ol.arabic {
120  list-style: decimal }
121
122ol.loweralpha {
123  list-style: lower-alpha }
124
125ol.upperalpha {
126  list-style: upper-alpha }
127
128ol.lowerroman {
129  list-style: lower-roman }
130
131ol.upperroman {
132  list-style: upper-roman }
133
134p.caption {
135  font-style: italic }
136
137p.credits {
138  font-style: italic ;
139  font-size: smaller }
140
141p.label {
142  white-space: nowrap }
143
144p.topic-title {
145  font-weight: bold }
146
147pre.address {
148  margin-bottom: 0 ;
149  margin-top: 0 ;
150  font-family: serif ;
151  font-size: 100% }
152
153pre.line-block {
154  font-family: serif ;
155  font-size: 100% }
156
157pre.literal-block, pre.doctest-block {
158  margin-left: 2em ;
159  margin-right: 2em ;
160  background-color: #eeeeee }
161
162span.classifier {
163  font-family: sans-serif ;
164  font-style: oblique }
165
166span.classifier-delimiter {
167  font-family: sans-serif ;
168  font-weight: bold }
169
170span.interpreted {
171  font-family: sans-serif }
172
173span.option-argument {
174  font-style: italic }
175
176span.pre {
177  white-space: pre }
178
179span.problematic {
180  color: red }
181
182table {
183  margin-top: 0.5em ;
184  margin-bottom: 0.5em }
185
186table.citation {
187  border-left: solid thin gray ;
188  padding-left: 0.5ex }
189
190table.docinfo {
191  margin: 2em 4em }
192
193table.footnote {
194  border-left: solid thin black ;
195  padding-left: 0.5ex }
196
197td, th {
198  padding-left: 0.5em ;
199  padding-right: 0.5em ;
200  vertical-align: top }
201
202th.docinfo-name, th.field-name {
203  font-weight: bold ;
204  text-align: left ;
205  white-space: nowrap }
206
207h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
208  font-size: 100% }
209
210tt, pre.literal-block, pre.doctest-block {
211  font-size: 115%;
212  line-height: 150% }
213
214ul.auto-toc {
215  list-style-type: none }
216
217</style>
218</head>
219<body>
220<div class="document">
221
222
223<div class="section" id="polymorphic-models-for-django">
224<h1><a class="toc-backref" href="#id1">Polymorphic Models for Django</a></h1>
225<div class="contents topic" id="table-of-contents">
226<p class="topic-title first">Table of Contents</p>
227<ul class="simple">
228<li><a class="reference internal" href="#polymorphic-models-for-django" id="id1">Polymorphic Models for Django</a></li>
229<li><a class="reference internal" href="#quickstart" id="id2">Quickstart</a></li>
230<li><a class="reference internal" href="#list-of-features" id="id3">List of Features</a></li>
231<li><a class="reference internal" href="#more-about-installation-testing" id="id4">More about Installation / Testing</a></li>
232<li><a class="reference internal" href="#more-polymorphic-functionality" id="id5">More Polymorphic Functionality</a></li>
233<li><a class="reference internal" href="#custom-managers-querysets-manager-inheritance" id="id6">Custom Managers, Querysets &amp; Manager Inheritance</a></li>
234<li><a class="reference internal" href="#performance-considerations" id="id7">Performance Considerations</a></li>
235<li><a class="reference internal" href="#restrictions-caveats" id="id8">Restrictions &amp; Caveats</a></li>
236<li><a class="reference internal" href="#project-status" id="id9">Project Status</a></li>
237<li><a class="reference internal" href="#links" id="id10">Links</a></li>
238</ul>
239</div>
240</div>
241<div class="section" id="quickstart">
242<h1><a class="toc-backref" href="#id2">Quickstart</a></h1>
243<div class="section" id="install">
244<h2>Install</h2>
245<p>After uncompressing (if necessary), in the directory &quot;...django_polymorphic&quot;,
246execute  (on Unix-like systems):</p>
247<pre class="literal-block">
248sudo python setup.py install
249</pre>
250</div>
251<div class="section" id="make-your-models-polymorphic">
252<h2>Make Your Models Polymorphic</h2>
253<p>Use <tt class="docutils literal">PolymorphicModel</tt> instead of Django's <tt class="docutils literal">models.Model</tt>, like so:</p>
254<pre class="literal-block">
255from polymorphic import PolymorphicModel
256
257class Project(PolymorphicModel):
258        topic = models.CharField(max_length=30)
259
260class ArtProject(Project):
261        artist = models.CharField(max_length=30)
262
263class ResearchProject(Project):
264        supervisor = models.CharField(max_length=30)
265</pre>
266<p>All models inheriting from your polymorphic models will be polymorphic as well.</p>
267</div>
268<div class="section" id="create-some-objects">
269<h2>Create some objects</h2>
270<pre class="doctest-block">
271&gt;&gt;&gt; Project.objects.create(topic=&quot;Department Party&quot;)
272&gt;&gt;&gt; ArtProject.objects.create(topic=&quot;Painting with Tim&quot;, artist=&quot;T. Turner&quot;)
273&gt;&gt;&gt; ResearchProject.objects.create(topic=&quot;Swallow Aerodynamics&quot;, supervisor=&quot;Dr. Winter&quot;)
274</pre>
275</div>
276<div class="section" id="get-polymorphic-query-results">
277<h2>Get polymorphic query results</h2>
278<pre class="doctest-block">
279&gt;&gt;&gt; Project.objects.all()
280[ &lt;Project:         id 1, topic &quot;Department Party&quot;&gt;,
281  &lt;ArtProject:      id 2, topic &quot;Painting with Tim&quot;, artist &quot;T. Turner&quot;&gt;,
282  &lt;ResearchProject: id 3, topic &quot;Swallow Aerodynamics&quot;, supervisor &quot;Dr. Winter&quot;&gt; ]
283</pre>
284<p>use <tt class="docutils literal">instance_of</tt> or <tt class="docutils literal">not_instance_of</tt> for narrowing the result to specific subtypes:</p>
285<pre class="doctest-block">
286&gt;&gt;&gt; Project.objects.instance_of(ArtProject)
287[ &lt;ArtProject:      id 2, topic &quot;Painting with Tim&quot;, artist &quot;T. Turner&quot;&gt; ]
288</pre>
289<pre class="doctest-block">
290&gt;&gt;&gt; Project.objects.instance_of(ArtProject) | Project.objects.instance_of(ResearchProject)
291[ &lt;ArtProject:      id 2, topic &quot;Painting with Tim&quot;, artist &quot;T. Turner&quot;&gt;,
292  &lt;ResearchProject: id 3, topic &quot;Swallow Aerodynamics&quot;, supervisor &quot;Dr. Winter&quot;&gt; ]
293</pre>
294<p>Polymorphic filtering: Get all projects where Mr. Turner is involved as an artist
295or supervisor (note the three underscores):</p>
296<pre class="doctest-block">
297&gt;&gt;&gt; Project.objects.filter(  Q(ArtProject___artist = 'T. Turner') | Q(ResearchProject___supervisor = 'T. Turner')  )
298[ &lt;ArtProject:      id 2, topic &quot;Painting with Tim&quot;, artist &quot;T. Turner&quot;&gt;,
299  &lt;ResearchProject: id 4, topic &quot;Color Use in Late Cubism&quot;, supervisor &quot;T. Turner&quot;&gt; ]
300</pre>
301<p>This is basically all you need to know, as django_polymorphic mostly
302works fully automatic and just delivers the expected (&quot;pythonic&quot;) results.</p>
303<p>Note: In all example output, above and below, for a nicer and more informative
304output the <tt class="docutils literal">ShowFieldType</tt> mixin has been used (documented below).</p>
305</div>
306</div>
307<div class="section" id="list-of-features">
308<h1><a class="toc-backref" href="#id3">List of Features</a></h1>
309<ul class="simple">
310<li>Fully automatic - generally makes sure that the same objects are
311returned from the database that were stored there, regardless how
312they are retrieved</li>
313<li>Only on models that request polymorphic behaviour (and the
314models inheriting from them)</li>
315<li>Full support for ForeignKeys, ManyToManyFields and OneToToneFields</li>
316<li>Filtering for classes, equivalent to python's isinstance():
317<tt class="docutils literal"><span class="pre">instance_of(...)</span></tt> and <tt class="docutils literal"><span class="pre">not_instance_of(...)</span></tt></li>
318<li>Polymorphic filtering/ordering etc., allowing the use of fields of
319derived models (&quot;ArtProject___artist&quot;)</li>
320<li>Support for user-defined custom managers</li>
321<li>Automatic inheritance of custom managers</li>
322<li>Support for user-defined custom queryset classes</li>
323<li>Non-polymorphic queries if needed, with no other change in
324features/behaviour</li>
325<li>Combining querysets of different types/models (&quot;qs3 = qs1 | qs2&quot;)</li>
326<li>Nice/informative display of polymorphic queryset results</li>
327</ul>
328</div>
329<div class="section" id="more-about-installation-testing">
330<h1><a class="toc-backref" href="#id4">More about Installation / Testing</a></h1>
331<div class="section" id="requirements">
332<h2>Requirements</h2>
333<p>Django 1.1 (or later) and Python 2.4 or later. This code has been tested
334on Django 1.1 / 1.2 / 1.3 and Python 2.4.6 / 2.5.4 / 2.6.4 on Linux.</p>
335</div>
336<div class="section" id="included-test-suite">
337<h2>Included Test Suite</h2>
338<p>The repository (or tar file) contains a complete Django project
339that may be used for tests or experiments, without any installation needed.</p>
340<p>To run the included test suite, in the directory &quot;...django_polymorphic&quot; execute:</p>
341<pre class="literal-block">
342./manage test polymorphic
343</pre>
344<p>The management command <tt class="docutils literal">pcmd.py</tt> in the app <tt class="docutils literal">pexp</tt> can be used
345for quick tests or experiments - modify this file (pexp/management/commands/pcmd.py)
346to your liking, then run:</p>
347<pre class="literal-block">
348./manage syncdb      # db is created in /var/tmp/... (settings.py)
349./manage pcmd
350</pre>
351</div>
352<div class="section" id="installation">
353<h2>Installation</h2>
354<p>In the directory &quot;...django_polymorphic&quot;, execute <tt class="docutils literal">sudo python setup.py install</tt>.</p>
355<p>Alternatively you can simply copy the <tt class="docutils literal">polymorphic</tt> subdirectory
356(under &quot;django_polymorphic&quot;) into your Django project dir
357(e.g. if you want to distribute your project with more 'batteries included').</p>
358<p>If you want to run the test cases in <cite>polymorphic/tests.py</cite>, you need to add
359<tt class="docutils literal">polymorphic</tt> to your INSTALLED_APPS setting.</p>
360<p>Django's ContentType framework (<tt class="docutils literal">django.contrib.contenttypes</tt>)
361needs to be listed in INSTALLED_APPS (usually it already is).</p>
362</div>
363</div>
364<div class="section" id="more-polymorphic-functionality">
365<h1><a class="toc-backref" href="#id5">More Polymorphic Functionality</a></h1>
366<p>In the examples below, these models are being used:</p>
367<pre class="literal-block">
368from polymorphic import PolymorphicModel
369
370class ModelA(PolymorphicModel):
371    field1 = models.CharField(max_length=10)
372
373class ModelB(ModelA):
374    field2 = models.CharField(max_length=10)
375
376class ModelC(ModelB):
377    field3 = models.CharField(max_length=10)
378</pre>
379<div class="section" id="filtering-for-classes-equivalent-to-python-s-isinstance">
380<h2>Filtering for classes (equivalent to python's isinstance() ):</h2>
381<pre class="doctest-block">
382&gt;&gt;&gt; ModelA.objects.instance_of(ModelB)
383.
384[ &lt;ModelB: id 2, field1 (CharField), field2 (CharField)&gt;,
385  &lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ]
386</pre>
387<p>In general, including or excluding parts of the inheritance tree:</p>
388<pre class="literal-block">
389ModelA.objects.instance_of(ModelB [, ModelC ...])
390ModelA.objects.not_instance_of(ModelB [, ModelC ...])
391</pre>
392<p>You can also use this feature in Q-objects (with the same result as above):</p>
393<pre class="doctest-block">
394&gt;&gt;&gt; ModelA.objects.filter( Q(instance_of=ModelB) )
395</pre>
396</div>
397<div class="section" id="polymorphic-filtering-for-fields-in-derived-classes">
398<h2>Polymorphic filtering (for fields in derived classes)</h2>
399<p>For example, cherrypicking objects from multiple derived classes
400anywhere in the inheritance tree, using Q objects (with the
401syntax: <tt class="docutils literal">exact model name + three _ + field name</tt>):</p>
402<pre class="doctest-block">
403&gt;&gt;&gt; ModelA.objects.filter(  Q(ModelB___field2 = 'B2') | Q(ModelC___field3 = 'C3')  )
404.
405[ &lt;ModelB: id 2, field1 (CharField), field2 (CharField)&gt;,
406  &lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ]
407</pre>
408</div>
409<div class="section" id="combining-querysets">
410<h2>Combining Querysets</h2>
411<p>Querysets could now be regarded as object containers that allow the
412aggregation of different object types, very similar to python
413lists - as long as the objects are accessed through the manager of
414a common base class:</p>
415<pre class="doctest-block">
416&gt;&gt;&gt; Base.objects.instance_of(ModelX) | Base.objects.instance_of(ModelY)
417.
418[ &lt;ModelX: id 1, field_x (CharField)&gt;,
419  &lt;ModelY: id 2, field_y (CharField)&gt; ]
420</pre>
421</div>
422<div class="section" id="manytomanyfield-foreignkey-onetoonefield">
423<h2>ManyToManyField, ForeignKey, OneToOneField</h2>
424<p>Relationship fields referring to polymorphic models work as
425expected: like polymorphic querysets they now always return the
426referred objects with the same type/class these were created and
427saved as.</p>
428<p>E.g., if in your model you define:</p>
429<pre class="literal-block">
430field1 = OneToOneField(ModelA)
431</pre>
432<p>then field1 may now also refer to objects of type <tt class="docutils literal">ModelB</tt> or <tt class="docutils literal">ModelC</tt>.</p>
433<p>A ManyToManyField example:</p>
434<pre class="literal-block">
435# The model holding the relation may be any kind of model, polymorphic or not
436class RelatingModel(models.Model):
437    many2many = models.ManyToManyField('ModelA')  # ManyToMany relation to a polymorphic model
438
439&gt;&gt;&gt; o=RelatingModel.objects.create()
440&gt;&gt;&gt; o.many2many.add(ModelA.objects.get(id=1))
441&gt;&gt;&gt; o.many2many.add(ModelB.objects.get(id=2))
442&gt;&gt;&gt; o.many2many.add(ModelC.objects.get(id=3))
443
444&gt;&gt;&gt; o.many2many.all()
445[ &lt;ModelA: id 1, field1 (CharField)&gt;,
446  &lt;ModelB: id 2, field1 (CharField), field2 (CharField)&gt;,
447  &lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ]
448</pre>
449</div>
450<div class="section" id="using-third-party-models-without-modifying-them">
451<h2>Using Third Party Models (without modifying them)</h2>
452<p>Third party models can be used as polymorphic models without
453restrictions by subclassing them. E.g. using a third party
454model as the root of a polymorphic inheritance tree:</p>
455<pre class="literal-block">
456from thirdparty import ThirdPartyModel
457
458class MyThirdPartyBaseModel(PolymorhpicModel, ThirdPartyModel):
459    pass    # or add fields
460</pre>
461<p>Or instead integrating the third party model anywhere into an
462existing polymorphic inheritance tree:</p>
463<pre class="literal-block">
464class MyBaseModel(SomePolymorphicModel):
465    my_field = models.CharField(max_length=10)
466
467class MyModelWithThirdParty(MyBaseModel, ThirdPartyModel):
468    pass    # or add fields
469</pre>
470</div>
471<div class="section" id="non-polymorphic-queries">
472<h2>Non-Polymorphic Queries</h2>
473<p>If you insert <tt class="docutils literal">.non_polymorphic()</tt> anywhere into the query chain, then
474django_polymorphic will simply leave out the final step of retrieving the
475real objects, and the manager/queryset will return objects of the type of
476the base class you used for the query, like vanilla Django would
477(<tt class="docutils literal">ModelA</tt> in this example).</p>
478<pre class="doctest-block">
479&gt;&gt;&gt; qs=ModelA.objects.non_polymorphic().all()
480&gt;&gt;&gt; qs
481[ &lt;ModelA: id 1, field1 (CharField)&gt;,
482  &lt;ModelA: id 2, field1 (CharField)&gt;,
483  &lt;ModelA: id 3, field1 (CharField)&gt; ]
484</pre>
485<p>There are no other changes in the behaviour of the queryset. For example,
486enhancements for <tt class="docutils literal">filter()</tt> or <tt class="docutils literal">instance_of()</tt> etc. still work as expected.
487If you do the final step yourself, you get the usual polymorphic result:</p>
488<pre class="doctest-block">
489&gt;&gt;&gt; ModelA.objects.get_real_instances(qs)
490[ &lt;ModelA: id 1, field1 (CharField)&gt;,
491  &lt;ModelB: id 2, field1 (CharField), field2 (CharField)&gt;,
492  &lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ]
493</pre>
494</div>
495<div class="section" id="about-queryset-methods">
496<h2>About Queryset Methods</h2>
497<ul class="simple">
498<li><tt class="docutils literal">annotate()</tt> and <tt class="docutils literal">aggregate()</tt> work just as usual, with the
499addition that the <tt class="docutils literal">ModelX___field</tt> syntax can be used for the
500keyword arguments (but not for the non-keyword arguments).</li>
501<li><tt class="docutils literal">order_by()</tt> now similarly supports the <tt class="docutils literal">ModelX___field</tt> syntax
502for specifying ordering through a field in a submodel.</li>
503<li><tt class="docutils literal">distinct()</tt> works as expected. It only regards the fields of
504the base class, but this should never make a difference.</li>
505<li><tt class="docutils literal">select_related()</tt> works just as usual, but it can not (yet) be used
506to select relations in derived models
507(like <tt class="docutils literal"><span class="pre">ModelA.objects.select_related('ModelC___fieldxy')</span></tt> )</li>
508<li><tt class="docutils literal">extra()</tt> works as expected (it returns polymorphic results) but
509currently has one restriction: The resulting objects are required to have
510a unique primary key within the result set - otherwise an error is thrown
511(this case could be made to work, however it may be mostly unneeded)..
512The keyword-argument &quot;polymorphic&quot; is no longer supported.
513You can get back the old non-polymorphic behaviour (before V1.0)
514by using <tt class="docutils literal"><span class="pre">ModelA.objects.non_polymorphic().extra(...)</span></tt>.</li>
515<li><tt class="docutils literal">get_real_instances()</tt> allows you to turn a
516queryset or list  of base model objects efficiently into the real objects.
517For example, you could do <tt class="docutils literal"><span class="pre">base_objects_queryset=ModelA.extra(...).non_polymorphic()</span></tt>
518and then call <tt class="docutils literal">real_objects=base_objects_queryset.get_real_instances()</tt>.Or alternatively
519.``real_objects=ModelA.objects..get_real_instances(base_objects_queryset_or_object_list)``</li>
520<li><tt class="docutils literal">values()</tt> &amp; <tt class="docutils literal">values_list()</tt> currently do not return polymorphic
521results. This may change in the future however. If you want to use these
522methods now, it's best if you use <tt class="docutils literal"><span class="pre">Model.base_objects.values...</span></tt> as
523this is guaranteed to not change.</li>
524<li><tt class="docutils literal">defer()</tt> and <tt class="docutils literal">only()</tt> are not yet supported (support will be added
525in the future).</li>
526</ul>
527</div>
528<div class="section" id="using-enhanced-q-objects-in-any-places">
529<h2>Using enhanced Q-objects in any Places</h2>
530<p>The queryset enhancements (e.g. <tt class="docutils literal">instance_of</tt>) only work as arguments
531to the member functions of a polymorphic queryset.  Occationally it may
532be useful to be able to use Q objects with these enhancements in other places.
533As Django doesn't understand these enhanced Q objects, you need to
534transform them manually into normal Q objects before you can feed them
535to a Django queryset or function:</p>
536<pre class="literal-block">
537normal_q_object = ModelA.translate_polymorphic_Q_object( Q(instance_of=Model2B) )
538</pre>
539<p>This function cannot be used at model creation time however (in models.py),
540as it may need to access the ContentTypes database table.</p>
541</div>
542<div class="section" id="nicely-displaying-polymorphic-querysets">
543<h2>Nicely Displaying Polymorphic Querysets</h2>
544<p>In order to get the output as seen in all examples here, you need to use the
545ShowFieldType class mixin:</p>
546<pre class="literal-block">
547from polymorphic import PolymorphicModel, ShowFieldType
548
549class ModelA(ShowFieldType, PolymorphicModel):
550    field1 = models.CharField(max_length=10)
551</pre>
552<p>You may also use ShowFieldContent or ShowFieldTypeAndContent to display
553additional information when printing querysets (or converting them to text).</p>
554<p>When showing field contents, they will be truncated to 20 characters. You can
555modify this behaviour by setting a class variable in your model like this:</p>
556<pre class="literal-block">
557class ModelA(ShowFieldType, PolymorphicModel):
558    polymorphic_showfield_max_field_width = 20
559    ...
560</pre>
561<p>Similarly, pre-V1.0 output formatting can be re-estated by using
562<tt class="docutils literal">polymorphic_showfield_old_format = True</tt>.</p>
563</div>
564</div>
565<div class="section" id="custom-managers-querysets-manager-inheritance">
566<h1><a class="toc-backref" href="#id6">Custom Managers, Querysets &amp; Manager Inheritance</a></h1>
567<div class="section" id="using-a-custom-manager">
568<h2>Using a Custom Manager</h2>
569<p>A nice feature of Django is the possibility to define one's own custom object managers.
570This is fully supported with django_polymorphic: For creating a custom polymorphic
571manager class, just derive your manager from <tt class="docutils literal">PolymorphicManager</tt> instead of
572<tt class="docutils literal">models.Manager</tt>. As with vanilla Django, in your model class, you should
573explicitly add the default manager first, and then your custom manager:</p>
574<pre class="literal-block">
575 from polymorphic import PolymorphicModel, PolymorphicManager
576
577class TimeOrderedManager(PolymorphicManager):
578     def get_query_set(self):
579         qs = super(TimeOrderedManager,self).get_query_set()
580         return qs.order_by('-start_date')        # order the queryset
581
582     def most_recent(self):
583         qs = self.get_query_set()                # get my ordered queryset
584         return qs[:10]                           # limit =&gt; get ten most recent entries
585
586 class Project(PolymorphicModel):
587     objects = PolymorphicManager()               # add the default polymorphic manager first
588     objects_ordered = TimeOrderedManager()       # then add your own manager
589     start_date = DateTimeField()                 # project start is this date/time
590</pre>
591<p>The first manager defined ('objects' in the example) is used by
592Django as automatic manager for several purposes, including accessing
593related objects. It must not filter objects and it's safest to use
594the plain <tt class="docutils literal">PolymorphicManager</tt> here.</p>
595</div>
596<div class="section" id="manager-inheritance">
597<h2>Manager Inheritance</h2>
598<p>Polymorphic models inherit/propagate all managers from their
599base models, as long as these are polymorphic. This means that all
600managers defined in polymorphic base models continue to work as
601expected in models inheriting from this base model:</p>
602<pre class="literal-block">
603from polymorphic import PolymorphicModel, PolymorphicManager
604
605class TimeOrderedManager(PolymorphicManager):
606     def get_query_set(self):
607         qs = super(TimeOrderedManager,self).get_query_set()
608         return qs.order_by('-start_date')        # order the queryset
609
610     def most_recent(self):
611         qs = self.get_query_set()                # get my ordered queryset
612         return qs[:10]                           # limit =&gt; get ten most recent entries
613
614 class Project(PolymorphicModel):
615     objects = PolymorphicManager()               # add the default polymorphic manager first
616     objects_ordered = TimeOrderedManager()       # then add your own manager
617     start_date = DateTimeField()                 # project start is this date/time
618
619 class ArtProject(Project):                       # inherit from Project, inheriting its fields and managers
620     artist = models.CharField(max_length=30)
621</pre>
622<p>ArtProject inherited the managers <tt class="docutils literal">objects</tt> and <tt class="docutils literal">objects_ordered</tt> from Project.</p>
623<p><tt class="docutils literal">ArtProject.objects_ordered.all()</tt> will return all art projects ordered
624regarding their start time and <tt class="docutils literal">ArtProject.objects_ordered.most_recent()</tt>
625will return the ten most recent art projects.
626.</p>
627</div>
628<div class="section" id="using-a-custom-queryset-class">
629<h2>Using a Custom Queryset Class</h2>
630<p>The <tt class="docutils literal">PolymorphicManager</tt> class accepts one initialization argument,
631which is the queryset class the manager should use. Just as with vanilla Django,
632you may define your own custom queryset classes. Just use PolymorphicQuerySet
633instead of Django's QuerySet as the base class:</p>
634<pre class="literal-block">
635from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet
636
637class MyQuerySet(PolymorphicQuerySet):
638    def my_queryset_method(...):
639        ...
640
641class MyModel(PolymorphicModel):
642    my_objects=PolymorphicManager(MyQuerySet)
643    ...
644</pre>
645</div>
646</div>
647<div class="section" id="performance-considerations">
648<h1><a class="toc-backref" href="#id7">Performance Considerations</a></h1>
649<p>The current implementation is rather simple and does not use any
650custom SQL or Django DB layer internals - it is purely based on the
651standard Django ORM.</p>
652<p>Specifically, the query:</p>
653<pre class="literal-block">
654result_objects = list( ModelA.objects.filter(...) )
655</pre>
656<p>performs one SQL query to retrieve <tt class="docutils literal">ModelA</tt> objects and one additional
657query for each unique derived class occurring in result_objects.
658The best case for retrieving 100 objects is 1 SQL query if all are
659class <tt class="docutils literal">ModelA</tt>. If 50 objects are <tt class="docutils literal">ModelA</tt> and 50 are <tt class="docutils literal">ModelB</tt>, then
660two queries are executed. The pathological worst case is 101 db queries if
661result_objects contains 100 different object types (with all of them
662subclasses of <tt class="docutils literal">ModelA</tt>).</p>
663<p>Usually, when Django users create their own polymorphic ad-hoc solution
664without a tool like django_polymorphic, this usually results in a variation of</p>
665<pre class="literal-block">
666result_objects = [ o.get_real_instance() for o in BaseModel.objects.filter(...) ]
667</pre>
668<p>which has very bad performance, as it introduces one additional
669SQL query for every object in the result which is not of class <tt class="docutils literal">BaseModel</tt>.</p>
670<p>Compared to these solutions, django_polymorphic has the advantage
671that it only needs one sql request per <em>object type</em>, and not <em>per object</em>.</p>
672<div class="section" id="performance-problems-with-postgresql-mysql-and-sqlite3">
673<span id="performance"></span><h2>Performance Problems with PostgreSQL, MySQL and SQLite3</h2>
674<p>Current relational DBM systems seem to have general problems with
675the SQL queries produced by object relational mappers like the Django
676ORM, if these use multi-table inheritance like Django's ORM does.
677The &quot;inner joins&quot; in these queries can perform very badly.
678This is independent of django_polymorphic and affects all uses of
679multi table Model inheritance.</p>
680<p>Concrete benchmark results are forthcoming (please see discussion forum).</p>
681<p>Please also see this <a class="reference external" href="http://www.jacobian.org/writing/concrete-inheritance/">post (and comments) from Jacob Kaplan-Moss</a>.</p>
682</div>
683</div>
684<div class="section" id="restrictions-caveats">
685<span id="restrictions"></span><h1><a class="toc-backref" href="#id8">Restrictions &amp; Caveats</a></h1>
686<ul class="simple">
687<li>Database Performance regarding concrete Model inheritance in general.
688Please see &quot;Performance Problems&quot; above.</li>
689<li>Queryset methods <tt class="docutils literal">values()</tt>, <tt class="docutils literal">values_list()</tt>, <tt class="docutils literal">select_related()</tt>,
690<tt class="docutils literal">defer()</tt> and <tt class="docutils literal">only()</tt> are not yet fully supported (see above).
691<tt class="docutils literal">extra()</tt> has one restriction: the resulting objects are required to have
692a unique primary key within the result set.</li>
693<li>Django Admin Integration: There currently is no specific admin integration,
694but it would most likely make sense to have one.</li>
695<li>Diamond shaped inheritance: There seems to be a general problem
696with diamond shaped multiple model inheritance with Django models
697(tested with V1.1 - V1.3).
698An example is here: <a class="reference external" href="http://code.djangoproject.com/ticket/10808">http://code.djangoproject.com/ticket/10808</a>.
699This problem is aggravated when trying to enhance models.Model
700by subclassing it instead of modifying Django core (as we do here
701with PolymorphicModel).</li>
702<li>The enhanced filter-definitions/Q-objects only work as arguments
703for the methods of the polymorphic querysets. Please see above
704for <tt class="docutils literal">translate_polymorphic_Q_object</tt>.</li>
705<li>A reference (<tt class="docutils literal">ContentType</tt>) to the real/leaf model is stored
706in the base model (the base model directly inheriting from
707PolymorphicModel). You need to be aware of this when using the
708<tt class="docutils literal">dumpdata</tt> management command or any other low-level
709database operations. E.g. if you rename models or apps or copy
710objects from one database to another, then Django's ContentType
711table needs to be corrected/copied too. This is of course generally
712the case for any models using Django's ContentType.</li>
713<li>Django 1.1 only - the names of polymorphic models must be unique
714in the whole project, even if they are in two different apps.
715This results from a restriction in the Django 1.1 &quot;related_name&quot;
716option (fixed in Django 1.2).</li>
717<li>Django 1.1 only - when ContentType is used in models, Django's
718seralisation or fixtures cannot be used (all polymorphic models
719use ContentType). This issue seems to be resolved for Django 1.2
720(changeset 11863: Fixed #7052, Added support for natural keys in serialization).<ul>
721<li><a class="reference external" href="http://code.djangoproject.com/ticket/7052">http://code.djangoproject.com/ticket/7052</a></li>
722<li><a class="reference external" href="http://stackoverflow.com/questions/853796/problems-with-contenttypes-when-loading-a-fixture-in-django">http://stackoverflow.com/questions/853796/problems-with-contenttypes-when-loading-a-fixture-in-django</a></li>
723</ul>
724</li>
725</ul>
726</div>
727<div class="section" id="project-status">
728<h1><a class="toc-backref" href="#id9">Project Status</a></h1>
729<p>Django_polymorphic works well for a considerable number of users now,
730and no major problems have shown up for many months.
731The API can be considered stable beginning with the V1.0 release.</p>
732</div>
733<div class="section" id="links">
734<h1><a class="toc-backref" href="#id10">Links</a></h1>
735<ul class="simple">
736<li><a class="reference external" href="http://code.djangoproject.com/wiki/ModelInheritance">http://code.djangoproject.com/wiki/ModelInheritance</a></li>
737<li><a class="reference external" href="http://lazypython.blogspot.com/2009/02/second-look-at-inheritance-and.html">http://lazypython.blogspot.com/2009/02/second-look-at-inheritance-and.html</a></li>
738<li><a class="reference external" href="http://www.djangosnippets.org/snippets/1031/">http://www.djangosnippets.org/snippets/1031/</a></li>
739<li><a class="reference external" href="http://www.djangosnippets.org/snippets/1034/">http://www.djangosnippets.org/snippets/1034/</a></li>
740<li><a class="reference external" href="http://groups.google.com/group/django-developers/browse_frm/thread/7d40ad373ebfa912/a20fabc661b7035d?lnk=gst&amp;q=model+inheritance+CORBA#a20fabc661b7035d">http://groups.google.com/group/django-developers/browse_frm/thread/7d40ad373ebfa912/a20fabc661b7035d?lnk=gst&amp;q=model+inheritance+CORBA#a20fabc661b7035d</a></li>
741<li><a class="reference external" href="http://groups.google.com/group/django-developers/browse_thread/thread/9bc2aaec0796f4e0/0b92971ffc0aa6f8?lnk=gst&amp;q=inheritance#0b92971ffc0aa6f8">http://groups.google.com/group/django-developers/browse_thread/thread/9bc2aaec0796f4e0/0b92971ffc0aa6f8?lnk=gst&amp;q=inheritance#0b92971ffc0aa6f8</a></li>
742<li><a class="reference external" href="http://groups.google.com/group/django-developers/browse_thread/thread/3947c594100c4adb/d8c0af3dacad412d?lnk=gst&amp;q=inheritance#d8c0af3dacad412d">http://groups.google.com/group/django-developers/browse_thread/thread/3947c594100c4adb/d8c0af3dacad412d?lnk=gst&amp;q=inheritance#d8c0af3dacad412d</a></li>
743<li><a class="reference external" href="http://groups.google.com/group/django-users/browse_thread/thread/52f72cffebb705e/b76c9d8c89a5574f">http://groups.google.com/group/django-users/browse_thread/thread/52f72cffebb705e/b76c9d8c89a5574f</a></li>
744<li><a class="reference external" href="http://peterbraden.co.uk/article/django-inheritance">http://peterbraden.co.uk/article/django-inheritance</a></li>
745<li><a class="reference external" href="http://www.hopelessgeek.com/2009/11/25/a-hack-for-multi-table-inheritance-in-django">http://www.hopelessgeek.com/2009/11/25/a-hack-for-multi-table-inheritance-in-django</a></li>
746<li><a class="reference external" href="http://stackoverflow.com/questions/929029/how-do-i-access-the-child-classes-of-an-object-in-django-without-knowing-the-name/929982#929982">http://stackoverflow.com/questions/929029/how-do-i-access-the-child-classes-of-an-object-in-django-without-knowing-the-name/929982#929982</a></li>
747<li><a class="reference external" href="http://stackoverflow.com/questions/1581024/django-inheritance-how-to-have-one-method-for-all-subclasses">http://stackoverflow.com/questions/1581024/django-inheritance-how-to-have-one-method-for-all-subclasses</a></li>
748<li><a class="reference external" href="http://groups.google.com/group/django-users/browse_thread/thread/cbdaf2273781ccab/e676a537d735d9ef?lnk=gst&amp;q=polymorphic#e676a537d735d9ef">http://groups.google.com/group/django-users/browse_thread/thread/cbdaf2273781ccab/e676a537d735d9ef?lnk=gst&amp;q=polymorphic#e676a537d735d9ef</a></li>
749<li><a class="reference external" href="http://groups.google.com/group/django-users/browse_thread/thread/52f72cffebb705e/bc18c18b2e83881e?lnk=gst&amp;q=model+inheritance#bc18c18b2e83881e">http://groups.google.com/group/django-users/browse_thread/thread/52f72cffebb705e/bc18c18b2e83881e?lnk=gst&amp;q=model+inheritance#bc18c18b2e83881e</a></li>
750<li><a class="reference external" href="http://code.djangoproject.com/ticket/10808">http://code.djangoproject.com/ticket/10808</a></li>
751<li><a class="reference external" href="http://code.djangoproject.com/ticket/7270">http://code.djangoproject.com/ticket/7270</a></li>
752</ul>
753</div>
754</div>
755</body>
756</html>