django-polymorphic/DOCS.html

754 lines
34 KiB
HTML

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.6: http://docutils.sourceforge.net/" />
<title></title>
<style type="text/css">
h1, h2, h3, h4 {
color: #47c;
}
a:hover { border-bottom: 1px solid #0066cc; }
a {color: #0066cc; text-decoration: none;}
tt {
color: #080;
}
blockquote tt {
color: #000
}
.first {
margin-top: 0 }
.last {
margin-bottom: 0 }
/*
a.toc-backref {
text-decoration: none ;
color: black }
*/
dd {
margin-bottom: 0.5em }
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.attention, div.caution, div.danger, div.error, div.hint,
div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title {
color: red ;
font-weight: bold ;
font-family: sans-serif }
div.hint p.admonition-title, div.important p.admonition-title,
div.note p.admonition-title, div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em }
div.footer, div.header {
font-size: smaller }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr {
width: 75% }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font-family: serif ;
font-size: 100% }
pre.line-block {
font-family: serif ;
font-size: 100% }
pre.literal-block, pre.doctest-block {
margin-left: 2em ;
margin-right: 2em ;
background-color: #eeeeee }
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option-argument {
font-style: italic }
span.pre {
white-space: pre }
span.problematic {
color: red }
table {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.citation {
border-left: solid thin gray ;
padding-left: 0.5ex }
table.docinfo {
margin: 2em 4em }
table.footnote {
border-left: solid thin black ;
padding-left: 0.5ex }
td, th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
th.docinfo-name, th.field-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap }
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
font-size: 100% }
tt, pre.literal-block, pre.doctest-block {
font-size: 115%;
line-height: 150% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document">
<div class="section" id="polymorphic-models-for-django">
<h1><a class="toc-backref" href="#id1">Polymorphic Models for Django</a></h1>
<div class="contents topic" id="table-of-contents">
<p class="topic-title first">Table of Contents</p>
<ul class="simple">
<li><a class="reference internal" href="#polymorphic-models-for-django" id="id1">Polymorphic Models for Django</a></li>
<li><a class="reference internal" href="#quickstart" id="id2">Quickstart</a></li>
<li><a class="reference internal" href="#more-about-installation-testing" id="id3">More about Installation / Testing</a></li>
<li><a class="reference internal" href="#more-polymorphic-functionality" id="id4">More Polymorphic Functionality</a></li>
<li><a class="reference internal" href="#custom-managers-querysets-manager-inheritance" id="id5">Custom Managers, Querysets &amp; Manager Inheritance</a></li>
<li><a class="reference internal" href="#performance-considerations" id="id6">Performance Considerations</a></li>
<li><a class="reference internal" href="#possible-optimizations" id="id7">Possible Optimizations</a></li>
<li><a class="reference internal" href="#restrictions-caveats" id="id8">Restrictions &amp; Caveats</a></li>
<li><a class="reference internal" href="#project-status" id="id9">Project Status</a></li>
<li><a class="reference internal" href="#links" id="id10">Links</a></li>
</ul>
</div>
</div>
<div class="section" id="quickstart">
<h1><a class="toc-backref" href="#id2">Quickstart</a></h1>
<div class="section" id="install">
<h2>Install</h2>
<p>After uncompressing (if necessary), in the directory &quot;django_polymorphic&quot;,
execute (on Unix-like systems):</p>
<pre class="literal-block">
sudo python setup.py install
</pre>
</div>
<div class="section" id="make-your-models-polymorphic">
<h2>Make Your Models Polymorphic</h2>
<p>Use <tt class="docutils literal">PolymorphicModel</tt> instead of Django's <tt class="docutils literal">models.Model</tt>, like so:</p>
<pre class="literal-block">
from polymorphic import PolymorphicModel
class Project(PolymorphicModel):
topic = models.CharField(max_length=30)
class ArtProject(Project):
artist = models.CharField(max_length=30)
class ResearchProject(Project):
supervisor = models.CharField(max_length=30)
</pre>
<p>All models inheriting from your polymorphic models will be polymorphic as well.</p>
</div>
<div class="section" id="create-some-objects">
<h2>Create some objects</h2>
<pre class="doctest-block">
&gt;&gt;&gt; Project.objects.create(topic=&quot;John's Gathering&quot;)
&gt;&gt;&gt; ArtProject.objects.create(topic=&quot;Sculpting with Tim&quot;, artist=&quot;T. Turner&quot;)
&gt;&gt;&gt; ResearchProject.objects.create(topic=&quot;Swallow Aerodynamics&quot;, supervisor=&quot;Dr. Winter&quot;)
</pre>
</div>
<div class="section" id="get-polymorphic-query-results">
<h2>Get polymorphic query results</h2>
<pre class="doctest-block">
&gt;&gt;&gt; Project.objects.all()
[ &lt;Project: id 1, topic: &quot;John's Gathering&quot;&gt;,
&lt;ArtProject: id 2, topic: &quot;Sculpting with Tim&quot;, artist: &quot;T. Turner&quot;&gt;,
&lt;ResearchProject: id 3, topic: &quot;Swallow Aerodynamics&quot;, supervisor: &quot;Dr. Winter&quot;&gt; ]
</pre>
<p>using instance_of and not_instance_of for narrowing the result to specific subtypes:</p>
<pre class="doctest-block">
&gt;&gt;&gt; Project.objects.instance_of(ArtProject)
[ &lt;ArtProject: id 2, topic: &quot;Sculpting with Tim&quot;, artist: &quot;T. Turner&quot;&gt; ]
</pre>
<pre class="doctest-block">
&gt;&gt;&gt; Project.objects.instance_of(ArtProject) | Project.objects.instance_of(ResearchProject)
[ &lt;ArtProject: id 2, topic: &quot;Sculpting with Tim&quot;, artist: &quot;T. Turner&quot;&gt;,
&lt;ResearchProject: id 3, topic: &quot;Swallow Aerodynamics&quot;, supervisor: &quot;Dr. Winter&quot;&gt; ]
</pre>
<p>Polymorphic filtering: Let's get all projects where Mr. Turner is involved as an artist
or supervisor (note the three underscores):</p>
<pre class="doctest-block">
&gt;&gt;&gt; Project.objects.filter( Q(ArtProject___artist = 'T. Turner') | Q(ResearchProject___supervisor = 'T. Turner') )
[ &lt;ArtProject: id 2, topic: &quot;Sculpting with Tim&quot;, artist: &quot;T. Turner&quot;&gt;,
&lt;ResearchProject: id 3, topic: &quot;History of Sculpting&quot;, supervisor: &quot;T. Turner&quot;&gt; ]
</pre>
</div>
<div class="section" id="what-s-more">
<h2>What's More?</h2>
<p>Most of Django's standard ORM functionality is available and works as expected.
ForeignKeys, ManyToManyFields and OneToToneFields to your polymorphic
models work as shey should (polymorphic).</p>
<p>In short, with django_polymorphic the Django models are much more &quot;pythonic&quot;, i.e.
they just work as you expect them to work: very similar to ordinary python classes
(which is not the case with vanilla Django model inheritance).</p>
<p>Note: In all example output, above and below, for a nicer and more informative
output the <cite>ShowFieldType</cite> mixin has been used (documented below).</p>
</div>
</div>
<div class="section" id="more-about-installation-testing">
<h1><a class="toc-backref" href="#id3">More about Installation / Testing</a></h1>
<div class="section" id="requirements">
<h2>Requirements</h2>
<p>Django 1.1 (or later) and Python 2.4 / 2.5 / 2.6. This code has been tested
on Django 1.1.1 / 1.2 beta and Python 2.4.6 / 2.5.4 / 2.6.4 on Linux.</p>
</div>
<div class="section" id="included-test-suite">
<h2>Included Test Suite</h2>
<p>The repository (or tar file) contains a complete Django project
that may be used for tests or experiments, without any installation needed.</p>
<p>To run the included test suite, execute:</p>
<pre class="literal-block">
./manage test polymorphic
</pre>
<p>The management command <tt class="docutils literal">pcmd.py</tt> in the app <tt class="docutils literal">pexp</tt> can be used for
experiments - modify this file (pexp/management/commands/pcmd.py)
to your liking, then run:</p>
<pre class="literal-block">
./manage syncdb # db is created in /var/tmp/... (settings.py)
./manage pcmd
</pre>
</div>
<div class="section" id="installation">
<h2>Installation</h2>
<p>In the directory &quot;django_polymorphic&quot;, execute <tt class="docutils literal">sudo python setup.py install</tt>.</p>
<p>Alternatively you can simply copy the <tt class="docutils literal">polymorphic</tt> directory
(under &quot;django_polymorphic&quot;) into your Django project dir
(e.g. if you want to distribute your project with more 'batteries included').</p>
<p>If you want to use the management command <tt class="docutils literal">polymorphic_dumpdata</tt>, then
you need to add <tt class="docutils literal">polymorphic</tt> to your INSTALLED_APPS setting. This is also
needed if you want to run the test cases in <cite>polymorphic/tests.py</cite>.</p>
<p>In any case, Django's ContentType framework (<tt class="docutils literal">django.contrib.contenttypes</tt>)
needs to be listed in INSTALLED_APPS (usually it already is).</p>
</div>
</div>
<div class="section" id="more-polymorphic-functionality">
<h1><a class="toc-backref" href="#id4">More Polymorphic Functionality</a></h1>
<p>In the examples below, these models are being used:</p>
<pre class="literal-block">
from polymorphic import PolymorphicModel
class ModelA(PolymorphicModel):
field1 = models.CharField(max_length=10)
class ModelB(ModelA):
field2 = models.CharField(max_length=10)
class ModelC(ModelB):
field3 = models.CharField(max_length=10)
</pre>
<div class="section" id="filtering-for-classes-equivalent-to-python-s-isinstance">
<h2>Filtering for classes (equivalent to python's isinstance() ):</h2>
<pre class="doctest-block">
&gt;&gt;&gt; ModelA.objects.instance_of(ModelB)
.
[ &lt;ModelB: id 2, field1 (CharField), field2 (CharField)&gt;,
&lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ]
</pre>
<p>In general, including or excluding parts of the inheritance tree:</p>
<pre class="literal-block">
ModelA.objects.instance_of(ModelB [, ModelC ...])
ModelA.objects.not_instance_of(ModelB [, ModelC ...])
</pre>
<p>You can also use this feature in Q-objects (with the same result as above):</p>
<pre class="doctest-block">
&gt;&gt;&gt; ModelA.objects.filter( Q(instance_of=ModelB) )
</pre>
</div>
<div class="section" id="polymorphic-filtering-for-fields-in-derived-classes">
<h2>Polymorphic filtering (for fields in derived classes)</h2>
<p>For example, cherrypicking objects from multiple derived classes
anywhere in the inheritance tree, using Q objects (with the
syntax: <tt class="docutils literal">exact model name + three _ + field name</tt>):</p>
<pre class="doctest-block">
&gt;&gt;&gt; ModelA.objects.filter( Q(ModelB___field2 = 'B2') | Q(ModelC___field3 = 'C3') )
.
[ &lt;ModelB: id 2, field1 (CharField), field2 (CharField)&gt;,
&lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ]
</pre>
</div>
<div class="section" id="combining-querysets-of-different-types-models">
<h2>Combining Querysets of different types/models</h2>
<p>Querysets may now be regarded as object containers that allow the
aggregation of different object types - very similar to python
lists (as long as the objects are accessed through the manager of
a common base class):</p>
<pre class="doctest-block">
&gt;&gt;&gt; Base.objects.instance_of(ModelX) | Base.objects.instance_of(ModelY)
.
[ &lt;ModelX: id 1, field_x (CharField)&gt;,
&lt;ModelY: id 2, field_y (CharField)&gt; ]
</pre>
</div>
<div class="section" id="manytomanyfield-foreignkey-onetoonefield">
<h2>ManyToManyField, ForeignKey, OneToOneField</h2>
<p>Relationship fields referring to polymorphic models work as
expected: like polymorphic querysets they now always return the
referred objects with the same type/class these were created and
saved as.</p>
<p>E.g., if in your model you define:</p>
<pre class="literal-block">
field1 = OneToOneField(ModelA)
</pre>
<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>
<p>A ManyToManyField example:</p>
<pre class="literal-block">
# The model holding the relation may be any kind of model, polymorphic or not
class RelatingModel(models.Model):
many2many = models.ManyToManyField('ModelA') # ManyToMany relation to a polymorphic model
&gt;&gt;&gt; o=RelatingModel.objects.create()
&gt;&gt;&gt; o.many2many.add(ModelA.objects.get(id=1))
&gt;&gt;&gt; o.many2many.add(ModelB.objects.get(id=2))
&gt;&gt;&gt; o.many2many.add(ModelC.objects.get(id=3))
&gt;&gt;&gt; o.many2many.all()
[ &lt;ModelA: id 1, field1 (CharField)&gt;,
&lt;ModelB: id 2, field1 (CharField), field2 (CharField)&gt;,
&lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ]
</pre>
</div>
<div class="section" id="using-third-party-models-without-modifying-them">
<h2>Using Third Party Models (without modifying them)</h2>
<p>Third party models can be used as polymorphic models without
restrictions by subclassing them. E.g. using a third party
model as the root of a polymorphic inheritance tree:</p>
<pre class="literal-block">
from thirdparty import ThirdPartyModel
class MyThirdPartyModel(PolymorhpicModel, ThirdPartyModel):
pass # or add fields
</pre>
<p>Or instead integrating the third party model anywhere into an
existing polymorphic inheritance tree:</p>
<pre class="literal-block">
class MyModel(SomePolymorphicModel):
my_field = models.CharField(max_length=10)
class MyModelWithThirdParty(MyModel, ThirdPartyModel):
pass # or add fields
</pre>
</div>
<div class="section" id="non-polymorphic-queries">
<h2>Non-Polymorphic Queries</h2>
<pre class="doctest-block">
&gt;&gt;&gt; ModelA.base_objects.all()
.
[ &lt;ModelA: id 1, field1 (CharField)&gt;,
&lt;ModelA: id 2, field1 (CharField)&gt;,
&lt;ModelA: id 3, field1 (CharField)&gt; ]
</pre>
<p>Each polymorphic model has 'base_objects' defined as a normal
Django manager. Of course, arbitrary custom managers may be
added to the models as well.</p>
</div>
<div class="section" id="about-queryset-methods">
<h2>About Queryset Methods</h2>
<ul class="simple">
<li><tt class="docutils literal">annotate()</tt> and <tt class="docutils literal">aggregate()</tt> work just as usual, with the
addition that the <tt class="docutils literal">ModelX___field</tt> syntax can be used for the
keyword arguments (but not for the non-keyword arguments).</li>
</ul>
<ul class="simple">
<li><tt class="docutils literal">order_by()</tt> now similarly supports the <tt class="docutils literal">ModelX___field</tt> syntax
for specifying ordering through a field in a submodel.</li>
</ul>
<ul class="simple">
<li><tt class="docutils literal">distinct()</tt> works as expected. It only regards the fields of
the base class, but this should never make a difference.</li>
</ul>
<ul class="simple">
<li><tt class="docutils literal">select_related()</tt> works just as usual, but it can not (yet) be used
to select relations in derived models
(like <tt class="docutils literal"><span class="pre">ModelA.objects.select_related('ModelC___fieldxy')</span></tt> )</li>
</ul>
<ul class="simple">
<li><tt class="docutils literal">extra()</tt> by default works exactly like the original version,
with the resulting queryset not being polymorphic. There is
experimental support for a polymorphic extra() via the keyword
argument <tt class="docutils literal">polymorphic=True</tt> (only the <tt class="docutils literal">where</tt> and
<tt class="docutils literal">order_by</tt> and <tt class="docutils literal">params</tt> arguments of extra() should be used then).
The behaviour of extra() may change in the future, so it's best if you use
<tt class="docutils literal"><span class="pre">base_objects=ModelA.base_objects.extra(...)</span></tt> instead if you want to
sure to get non-polymorphic behaviour.</li>
</ul>
<ul class="simple">
<li><tt class="docutils literal">get_real_instances(base_objects_list_or_queryset)</tt> allows you to turn a
queryset or list of base model objects efficiently into the real objects.
For example, you could do <tt class="docutils literal"><span class="pre">base_objects=ModelA.base_objects.extra(...)</span></tt> and
then call <tt class="docutils literal">real_objects=ModelA.objects.get_real_instances(base_objects)</tt>.</li>
</ul>
<ul class="simple">
<li><tt class="docutils literal">values()</tt> &amp; <tt class="docutils literal">values_list()</tt> currently do not return polymorphic
results. This may change in the future however. If you want to use these
methods now, it's best if you use <tt class="docutils literal"><span class="pre">Model.base_objects.values...</span></tt> as
this is guaranteed to not change.</li>
</ul>
<ul class="simple">
<li><tt class="docutils literal">defer()</tt> and <tt class="docutils literal">only()</tt> are not yet supported (support will be added
in the future).</li>
</ul>
</div>
<div class="section" id="using-enhanced-q-objects-in-any-places">
<h2>Using enhanced Q-objects in any Places</h2>
<p>Sometimes it would be nice to be able to use the enhanced filter-definitions/Q-objects
outside of polymorphic models/querysets. Example (using <tt class="docutils literal">limit_choices_to</tt>
to filter the selection of objects in the admin):</p>
<pre class="literal-block">
class MyModel(models.Model):
somekey = model.ForeignKey(Model2A,
limit_choices_to = Q(instance_of=Model2B) )
</pre>
<p><tt class="docutils literal">instance_of</tt> is a django_polymorphic-specific enhancement of Q objects, which the
vanilla django function <tt class="docutils literal">ForeignKey</tt> cannot process. In such cases you can do:</p>
<pre class="literal-block">
from polymorphic import translate_polymorphic_Q_object
class MyModel(models.Model):
somekey = model.ForeignKey(Model2A,
limit_choices_to = translate_polymorphic_Q_object( Model2A, Q(instance_of=Model2B) ) )
</pre>
</div>
<div class="section" id="nicely-displaying-polymorphic-querysets">
<h2>Nicely Displaying Polymorphic Querysets</h2>
<p>In order to get the output as seen in all examples here, you need to use the
ShowFieldType class mixin:</p>
<pre class="literal-block">
from polymorphic import PolymorphicModel, ShowFieldType
class ModelA(ShowFieldType, PolymorphicModel):
field1 = models.CharField(max_length=10)
</pre>
<p>You may also use ShowFieldContent or ShowFieldTypeAndContent to display
additional information when printing querysets (or converting them to text).</p>
</div>
</div>
<div class="section" id="custom-managers-querysets-manager-inheritance">
<h1><a class="toc-backref" href="#id5">Custom Managers, Querysets &amp; Manager Inheritance</a></h1>
<div class="section" id="using-a-custom-manager">
<h2>Using a Custom Manager</h2>
<p>A nice feature of Django is the possibility to define one's own custom object managers.
This is fully supported with django_polymorphic: For creating a custom polymorphic
manager class, just derive your manager from <tt class="docutils literal">PolymorphicManager</tt> instead of
<tt class="docutils literal">models.Manager</tt>. Just as with vanilla Django, in your model class, you should
explicitly add the default manager first, and then your custom manager:</p>
<pre class="literal-block">
from polymorphic import PolymorphicModel, PolymorphicManager
class MyOrderedManager(PolymorphicManager):
def get_query_set(self):
return super(MyOrderedManager,self).get_query_set().order_by('some_field')
class MyModel(PolymorphicModel):
objects = PolymorphicManager() # add the default polymorphic manager first
ordered_objects = MyOrderedManager() # then add your own manager
</pre>
<p>The first manager defined ('objects' in the example) is used by
Django as automatic manager for several purposes, including accessing
related objects. It must not filter objects and it's safest to use
the plain <tt class="docutils literal">PolymorphicManager</tt> here.</p>
</div>
<div class="section" id="manager-inheritance">
<h2>Manager Inheritance</h2>
<p>Polymorphic models inherit/propagate all managers from their
base models, as long as these are polymorphic. This means that all
managers defined in polymorphic base models work just the same as if
they were defined in the new model.</p>
<p>An example (inheriting from MyModel above):</p>
<pre class="literal-block">
class MyModel2(MyModel):
pass
# Managers inherited from MyModel:
# the regular 'objects' manager and the custom 'ordered_objects' manager
&gt;&gt;&gt; MyModel2.objects.all()
&gt;&gt;&gt; MyModel2.ordered_objects.all()
</pre>
</div>
<div class="section" id="using-a-custom-queryset-class">
<h2>Using a Custom Queryset Class</h2>
<p>The <tt class="docutils literal">PolymorphicManager</tt> class accepts one initialization argument,
which is the queryset class the manager should use. Just as with vanilla Django,
you may define your own custom queryset classes. Just use PolymorphicQuerySet
instead of Django's QuerySet as the base class:</p>
<pre class="literal-block">
from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet
class MyQuerySet(PolymorphicQuerySet):
def my_queryset_method(...):
...
class MyModel(PolymorphicModel):
my_objects=PolymorphicManager(MyQuerySet)
...
</pre>
</div>
</div>
<div class="section" id="performance-considerations">
<h1><a class="toc-backref" href="#id6">Performance Considerations</a></h1>
<p>The current implementation is pretty simple and does not use any
custom SQL or Django DB layer internals - it is purely based on the
standard Django ORM. Right now the query</p>
<pre class="literal-block">
result_objects = list( ModelA.objects.filter(...) )
</pre>
<p>performs one SQL query to retrieve <tt class="docutils literal">ModelA</tt> objects and one additional
query for each unique derived class occurring in result_objects.
The best case for retrieving 100 objects is 1 SQL query if all are
class <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
two queries are executed. The pathological worst case is 101 db queries if
result_objects contains 100 different object types (with all of them
subclasses of <tt class="docutils literal">ModelA</tt>).</p>
<p>Performance ist relative: when Django users create their own
polymorphic ad-hoc solution (without a tool like <tt class="docutils literal">django_polymorphic</tt>),
this usually results in a variation of</p>
<pre class="literal-block">
result_objects = [ o.get_real_instance() for o in BaseModel.objects.filter(...) ]
</pre>
<p>which has really bad performance. Relative to this, the
performance of the current <tt class="docutils literal">django_polymorphic</tt> is pretty good.
It's probably efficient enough for the majority of use cases.</p>
<p>Chunking: The implementation always requests objects in chunks of
size <tt class="docutils literal">Polymorphic_QuerySet_objects_per_request</tt>. This limits the
complexity/duration for each query, including the pathological cases.</p>
</div>
<div class="section" id="possible-optimizations">
<h1><a class="toc-backref" href="#id7">Possible Optimizations</a></h1>
<p><tt class="docutils literal">PolymorphicQuerySet</tt> can be optimized to require only one SQL query
for the queryset evaluation and retrieval of all objects.</p>
<p>Basically, what ist needed is a possibility to pull in the fields
from all relevant sub-models with one SQL query. However, some deeper
digging into the Django database layer will be required in order to
make this happen.</p>
<p>An optimized version might require an SQL database. For non-SQL databases
the implementation could fall back to the current ORM-only
implementation.</p>
<div class="section" id="sql-complexity-of-an-optimized-implementation">
<h2>SQL Complexity of an Optimized Implementation</h2>
<p>With only one SQL query, one SQL join for each possible subclass
would be needed (<tt class="docutils literal">BaseModel.__subclasses__()</tt>, recursively).
With two SQL queries, the number of joins could be reduced to the
number of actuallly occurring subclasses in the result. A final
implementation might want to use one query only if the number of
possible subclasses (and therefore joins) is not too large, and
two queries otherwise (using the first query to determine the
actually occurring subclasses, reducing the number of joins for
the second).</p>
<p>The number of joins needed for polymorphic object retrieval might
raise concerns regarding the efficiency of these database
queries. It seems likely however, that the increased number of joins
is no problem for the supported DBM systems in all realistic use cases.
Should the number of joins of the more extreme use cases turn out to
be problematic, it is possible to split any problematic query into, for example,
two queries with only half the number of joins each.</p>
</div>
<div class="section" id="in-general">
<h2>In General</h2>
<p>Let's not forget that the above is just about optimization.
The current implementation already works well - and perhaps well
enough for the majority of applications.</p>
<p>Also, it seems that further optimization (down to one DB request)
would be restricted to a relatively small area of the code, and
be mostly independent from the rest of the module.
So it seems this optimization can be done at any later time
(like when it's needed).</p>
</div>
</div>
<div class="section" id="restrictions-caveats">
<span id="restrictions"></span><h1><a class="toc-backref" href="#id8">Restrictions &amp; Caveats</a></h1>
<ul class="simple">
<li>The queryset methods <tt class="docutils literal">values()</tt>, <tt class="docutils literal">values_list()</tt>, <tt class="docutils literal">select_related()</tt>,
<tt class="docutils literal">defer()</tt> and <tt class="docutils literal">only()</tt> are not yet fully supported (see above)</li>
</ul>
<ul class="simple">
<li>Django Admin Integration: There currently is no specific admin integration,
but it would most likely make sense to have one.</li>
</ul>
<ul class="simple">
<li>Diamond shaped inheritance: There seems to be a general problem
with diamond shaped multiple model inheritance with Django models
(tested with V1.1 - V1.3).
An example is here: <a class="reference external" href="http://code.djangoproject.com/ticket/10808">http://code.djangoproject.com/ticket/10808</a>.
This problem is aggravated when trying to enhance models.Model
by subclassing it instead of modifying Django core (as we do here
with PolymorphicModel).</li>
</ul>
<ul class="simple">
<li>The enhanced filter-definitions/Q-objects only work as arguments
for the methods of the polymorphic querysets. Please see above
for <tt class="docutils literal">translate_polymorphic_Q_object</tt>.</li>
</ul>
<ul class="simple">
<li>Django 1.1 only - the names of polymorphic models must be unique
in the whole project, even if they are in two different apps.
This results from a restriction in the Django 1.1 &quot;related_name&quot;
option (fixed in Django 1.2).</li>
</ul>
<ul class="simple">
<li>Django 1.1 only - when ContentType is used in models, Django's
seralisation or fixtures cannot be used (all polymorphic models
use ContentType). This issue seems to be resolved for Django 1.2
(changeset 11863: Fixed #7052, Added support for natural keys in serialization).<ul>
<li><a class="reference external" href="http://code.djangoproject.com/ticket/7052">http://code.djangoproject.com/ticket/7052</a></li>
<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>
</ul>
</li>
</ul>
<ul class="simple">
<li>A reference (<tt class="docutils literal">ContentType</tt>) to the real/leaf model is stored
in the base model (the base model directly inheriting from
PolymorphicModel). You need to be aware of this when using the
<tt class="docutils literal">dumpdata</tt> management command or any other low-level
database operations. E.g. if you rename models or apps or copy
objects from one database to another, then Django's ContentType
table needs to be corrected/copied too. This is of course generally
the case for any models using Django's ContentType.</li>
</ul>
</div>
<div class="section" id="project-status">
<h1><a class="toc-backref" href="#id9">Project Status</a></h1>
<p>Django_polymorphic works well for a considerable number of users now,
and no major problems have shown up for many months.
The API can be considered stable beginning with this release.</p>
</div>
<div class="section" id="links">
<h1><a class="toc-backref" href="#id10">Links</a></h1>
<ul class="simple">
<li><a class="reference external" href="http://code.djangoproject.com/wiki/ModelInheritance">http://code.djangoproject.com/wiki/ModelInheritance</a></li>
<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>
<li><a class="reference external" href="http://www.djangosnippets.org/snippets/1031/">http://www.djangosnippets.org/snippets/1031/</a></li>
<li><a class="reference external" href="http://www.djangosnippets.org/snippets/1034/">http://www.djangosnippets.org/snippets/1034/</a></li>
<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>
<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>
<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>
<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>
<li><a class="reference external" href="http://peterbraden.co.uk/article/django-inheritance">http://peterbraden.co.uk/article/django-inheritance</a></li>
<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>
<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>
<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>
<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>
<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>
<li><a class="reference external" href="http://code.djangoproject.com/ticket/10808">http://code.djangoproject.com/ticket/10808</a></li>
<li><a class="reference external" href="http://code.djangoproject.com/ticket/7270">http://code.djangoproject.com/ticket/7270</a></li>
</ul>
</div>
</div>
</body>
</html>