fix_request_path_info
Bert Constantin 2010-11-11 17:11:01 +01:00
parent 748d10d2d5
commit ca329ff9b4
8 changed files with 309 additions and 275 deletions

View File

@ -7,10 +7,11 @@
<title></title> <title></title>
<style type="text/css"> <style type="text/css">
h1, h2, h3, h4 { h1, h2, h3, h4,
#table-of-contents
{
color: #47c; color: #47c;
} }
h1 { padding-top: 15px; } h1 { padding-top: 15px; }
h2 { padding-top: 10px; } h2 { padding-top: 10px; }
h3 { padding-top: 7px; } h3 { padding-top: 7px; }
@ -18,6 +19,10 @@ h3 { padding-top: 7px; }
a:hover { border-bottom: 1px solid #0066cc; } a:hover { border-bottom: 1px solid #0066cc; }
a {color: #0066cc; text-decoration: none;} a {color: #0066cc; text-decoration: none;}
li {
padding-top: 5px;
padding-bottom: 5px;
}
tt { tt {
color: #080; color: #080;
@ -221,32 +226,45 @@ ul.auto-toc {
<div class="section" id="changelog"> <div class="section" id="changelog">
<h1>Changelog</h1> <h1>Changelog</h1>
<div class="section" id="v1-0-beta-2"> <div class="section" id="v1-0-beta-2">
<h2>2010-10-25 V1.0 Beta 2</h2> <h2>2010-11-11 V1.0 Beta 2</h2>
<div class="section" id="this-is-a-v1-0-beta-testing-release"> <div class="section" id="this-is-a-v1-0-testing-release">
<h3>This is a V1.0 Beta/Testing Release</h3> <h3>This is a V1.0 Testing Release</h3>
<p>The release contains a considerable amount of changes in some of the more <p>Beta 2 accumulated somewhat more changes than intended, and also
critical parts of the software. It's intended for testing and development has been delayed by DBMS benchmark testing I wanted to do on model
environments and not for production environments. For these, it's best to inheritance. These benchmarks show that there are considerable
wait a few weeks for the proper V1.0 release, to allow some time for any problems with concrete model inheritance and contemporary DBM systems.
potential problems to show up (if they exist).</p> The results will be forthcoming on the google discussion forum.</p>
<p>Please also see:
<a class="reference external" href="http://www.jacobian.org/writing/concrete-inheritance/">http://www.jacobian.org/writing/concrete-inheritance/</a></p>
<p>The API should be stable now with Beta 2, so it's just about potential
bugfixes from now on regarding V1.0.</p>
<p>Beta 2 is still intended for testing and development environments and not
for production. No complaints have been heard regarding Beta 1 however,
and Beta 1 is used on a few production sites by some enterprising users.</p>
<p>There will be a release candidate for V1.0 in the very near future.</p>
</div> </div>
<div class="section" id="new-features-and-api-changes-since-beta-1"> <div class="section" id="new-features-and-api-changes-in-beta-2-since-beta-1">
<h3>New Features and API changes since Beta 1</h3> <h3>New Features and API changes in Beta 2 since Beta 1</h3>
<ul class="simple"> <ul>
<li>API CHANGE: <tt class="docutils literal">.extra()</tt> has been re-implemented. Now it's polymorphic by <li><p class="first">API CHANGE: <tt class="docutils literal">.extra()</tt> has been re-implemented. Now it's polymorphic by
default and works (nearly) without restrictions (please see docs). This is an default and works (nearly) without restrictions (please see docs). This is a (very)
incompatible API change regarding previous versions of django_polymorphic. incompatible API change regarding previous versions of django_polymorphic.
Support for the <tt class="docutils literal">polymorphic</tt> keyword parameter has been removed. Support for the <tt class="docutils literal">polymorphic</tt> keyword parameter has been removed.
You can get back the non-polymorphic behaviour by using You can get back the non-polymorphic behaviour by using
<tt class="docutils literal"><span class="pre">ModelA.objects.non_polymorphic().extra()</span></tt>.</li> <tt class="docutils literal"><span class="pre">ModelA.objects.non_polymorphic().extra(...)</span></tt>.</p>
</ul> </li>
<ul class="simple"> <li><p class="first">API CHANGE: <tt class="docutils literal">ShowFieldContent</tt> and <tt class="docutils literal">ShowFieldTypeAndContent</tt> now
<li><tt class="docutils literal">.non_polymorphic()</tt> queryset member function added. This is preferable to use a slightly different output format. If this causes too much trouble for
your test cases, you can get the old behaviour back (mostly) by adding
<tt class="docutils literal">polymorphic_showfield_old_format = True</tt> to your model definitions.
<tt class="docutils literal"><span class="pre">ShowField...</span></tt> now also produces more informative output for custom
primary keys.</p>
</li>
<li><p class="first"><tt class="docutils literal">.non_polymorphic()</tt> queryset member function added. This is preferable to
using <tt class="docutils literal"><span class="pre">.base_objects...</span></tt>, as it just makes the resulting queryset non-polymorphic using <tt class="docutils literal"><span class="pre">.base_objects...</span></tt>, as it just makes the resulting queryset non-polymorphic
and does not change anything else in the behaviour of the manager used (while and does not change anything else in the behaviour of the manager used (while
<tt class="docutils literal">.base_objects</tt> is just a different manager).</li> <tt class="docutils literal">.base_objects</tt> is just a different manager).</p>
</ul> </li>
<ul>
<li><p class="first"><tt class="docutils literal">.get_real_instances()</tt>: implementation modified to allow the following <li><p class="first"><tt class="docutils literal">.get_real_instances()</tt>: implementation modified to allow the following
more simple and intuitive use:</p> more simple and intuitive use:</p>
<pre class="literal-block"> <pre class="literal-block">
@ -258,16 +276,29 @@ more simple and intuitive use:</p>
&gt;&gt;&gt; ModelA.objects.all() &gt;&gt;&gt; ModelA.objects.all()
</pre> </pre>
</li> </li>
<li><p class="first">misc changes/improvements</p>
</li>
</ul> </ul>
</div>
<div class="section" id="bugfixes">
<h3>Bugfixes</h3>
<ul class="simple"> <ul class="simple">
<li>misc changes/improvements</li> <li>Custom fields could cause problems when used as the primary key.
In derived models, Django's automatic &quot;.pk&quot; field does not always work
correctly for such custom fields: &quot;some_object.pk&quot; and &quot;some_object.id&quot;
return different results (which they shouldn't, as pk should always be just
an alias for the primary key field). It's unclear yet if the problem lies in
Django or the affected custom fields. Regardless, the problem resulting
from this has been fixed with a small workaround.
&quot;python manage.py test polymorphic&quot; also tests and reports on this problem now.
Thanks to Mathieu Steele for reporting and the test case.</li>
</ul> </ul>
</div> </div>
</div> </div>
<hr class="docutils" /> <hr class="docutils" />
<div class="section" id="v1-0-beta-1"> <div class="section" id="v1-0-beta-1">
<h2>2010-10-18 V1.0 Beta 1</h2> <h2>2010-10-18 V1.0 Beta 1</h2>
<div class="section" id="id1"> <div class="section" id="this-is-a-v1-0-beta-testing-release">
<h3>This is a V1.0 Beta/Testing Release</h3> <h3>This is a V1.0 Beta/Testing Release</h3>
<p>This release is mostly a cleanup and maintenance release that also <p>This release is mostly a cleanup and maintenance release that also
improves a number of minor things and fixes one (non-critical) bug.</p> improves a number of minor things and fixes one (non-critical) bug.</p>
@ -315,10 +346,10 @@ transform the result to its polymorphic equivalent.</p>
</li> </li>
</ul> </ul>
</div> </div>
<div class="section" id="bugfixes"> <div class="section" id="id1">
<h3>Bugfixes</h3> <h3>Bugfixes</h3>
<ul class="simple"> <ul class="simple">
<li>removed requirement for primary key to be an IntegerField. <li>Removed requirement for primary key to be an IntegerField.
Thanks to Mathieu Steele and Malthe Borch.</li> Thanks to Mathieu Steele and Malthe Borch.</li>
</ul> </ul>
</div> </div>
@ -329,9 +360,10 @@ Thanks to Mathieu Steele and Malthe Borch.</li>
and has been disabled, as the regular Django dumpdata command now automatically and has been disabled, as the regular Django dumpdata command now automatically
works correctly with polymorphic models (for all supported versions of Django).</p> works correctly with polymorphic models (for all supported versions of Django).</p>
<p><strong>Output of Queryset or Object Printing</strong></p> <p><strong>Output of Queryset or Object Printing</strong></p>
<p>In order to improve compatibility with vanilla Django, printing quersets does not use <p>In order to improve compatibility with vanilla Django, printing quersets
django_polymorphic's pretty printing by default anymore. (__repr__ and __unicode__) does not use django_polymorphic's pretty printing
To get the old behaviour when printing querysets, you need to replace your model definition:</p> by default anymore. To get the old behaviour when printing querysets,
you need to replace your model definition:</p>
<pre class="doctest-block"> <pre class="doctest-block">
&gt;&gt;&gt; class Project(PolymorphicModel): &gt;&gt;&gt; class Project(PolymorphicModel):
</pre> </pre>

View File

@ -3,21 +3,36 @@
Changelog Changelog
++++++++++ ++++++++++
2010-11-01 V1.0 Beta 2 2010-11-11 V1.0 Beta 2
====================== ======================
This is a V1.0 Beta/Testing Release This is a V1.0 Testing Release
----------------------------------- ------------------------------
Beta 2 accumulated somewhat more changes than intended. It's still Beta 2 accumulated somewhat more changes than intended, and also
intended for testing and development environments and not for production has been delayed by DBMS benchmark testing I wanted to do on model
(it's best to wait for the final V1.0 for production servers). inheritance. These benchmarks show that there are considerable
problems with concrete model inheritance and contemporary DBM systems.
The results will be forthcoming on the google discussion forum.
New Features and API changes since Beta 1 Please also see:
----------------------------------------- http://www.jacobian.org/writing/concrete-inheritance/
The API should be stable now with Beta 2, so it's just about potential
bugfixes from now on regarding V1.0.
Beta 2 is still intended for testing and development environments and not
for production. No complaints have been heard regarding Beta 1 however,
and Beta 1 is used on a few production sites by some enterprising users.
There will be a release candidate for V1.0 in the very near future.
New Features and API changes in Beta 2 since Beta 1
---------------------------------------------------
* API CHANGE: ``.extra()`` has been re-implemented. Now it's polymorphic by * API CHANGE: ``.extra()`` has been re-implemented. Now it's polymorphic by
default and works (nearly) without restrictions (please see docs). This is an default and works (nearly) without restrictions (please see docs). This is a (very)
incompatible API change regarding previous versions of django_polymorphic. incompatible API change regarding previous versions of django_polymorphic.
Support for the ``polymorphic`` keyword parameter has been removed. Support for the ``polymorphic`` keyword parameter has been removed.
You can get back the non-polymorphic behaviour by using You can get back the non-polymorphic behaviour by using
@ -27,7 +42,7 @@ New Features and API changes since Beta 1
use a slightly different output format. If this causes too much trouble for use a slightly different output format. If this causes too much trouble for
your test cases, you can get the old behaviour back (mostly) by adding your test cases, you can get the old behaviour back (mostly) by adding
``polymorphic_showfield_old_format = True`` to your model definitions. ``polymorphic_showfield_old_format = True`` to your model definitions.
``ShowField...`` also produces more informative output for custom ``ShowField...`` now also produces more informative output for custom
primary keys. primary keys.
* ``.non_polymorphic()`` queryset member function added. This is preferable to * ``.non_polymorphic()`` queryset member function added. This is preferable to
@ -58,6 +73,7 @@ Bugfixes
Django or the affected custom fields. Regardless, the problem resulting Django or the affected custom fields. Regardless, the problem resulting
from this has been fixed with a small workaround. from this has been fixed with a small workaround.
"python manage.py test polymorphic" also tests and reports on this problem now. "python manage.py test polymorphic" also tests and reports on this problem now.
Thanks to Mathieu Steele for reporting and the test case.
------------------------------------------------------------------ ------------------------------------------------------------------
@ -134,9 +150,10 @@ works correctly with polymorphic models (for all supported versions of Django).
**Output of Queryset or Object Printing** **Output of Queryset or Object Printing**
In order to improve compatibility with vanilla Django, printing quersets does not use In order to improve compatibility with vanilla Django, printing quersets
django_polymorphic's pretty printing by default anymore. (__repr__ and __unicode__) does not use django_polymorphic's pretty printing
To get the old behaviour when printing querysets, you need to replace your model definition: by default anymore. To get the old behaviour when printing querysets,
you need to replace your model definition:
>>> class Project(PolymorphicModel): >>> class Project(PolymorphicModel):

141
DOCS.html
View File

@ -232,10 +232,9 @@ ul.auto-toc {
<li><a class="reference internal" href="#more-polymorphic-functionality" id="id5">More Polymorphic Functionality</a></li> <li><a class="reference internal" href="#more-polymorphic-functionality" id="id5">More Polymorphic Functionality</a></li>
<li><a class="reference internal" href="#custom-managers-querysets-manager-inheritance" id="id6">Custom Managers, Querysets &amp; Manager Inheritance</a></li> <li><a class="reference internal" href="#custom-managers-querysets-manager-inheritance" id="id6">Custom Managers, Querysets &amp; Manager Inheritance</a></li>
<li><a class="reference internal" href="#performance-considerations" id="id7">Performance Considerations</a></li> <li><a class="reference internal" href="#performance-considerations" id="id7">Performance Considerations</a></li>
<li><a class="reference internal" href="#possible-optimizations" id="id8">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="#restrictions-caveats" id="id9">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="#project-status" id="id10">Project Status</a></li> <li><a class="reference internal" href="#links" id="id10">Links</a></li>
<li><a class="reference internal" href="#links" id="id11">Links</a></li>
</ul> </ul>
</div> </div>
</div> </div>
@ -269,8 +268,8 @@ class ResearchProject(Project):
<div class="section" id="create-some-objects"> <div class="section" id="create-some-objects">
<h2>Create some objects</h2> <h2>Create some objects</h2>
<pre class="doctest-block"> <pre class="doctest-block">
&gt;&gt;&gt; Project.objects.create(topic=&quot;John's Gathering&quot;) &gt;&gt;&gt; Project.objects.create(topic=&quot;Department Party&quot;)
&gt;&gt;&gt; ArtProject.objects.create(topic=&quot;Sculpting with Tim&quot;, artist=&quot;T. Turner&quot;) &gt;&gt;&gt; ArtProject.objects.create(topic=&quot;Painting with Tim&quot;, artist=&quot;T. Turner&quot;)
&gt;&gt;&gt; ResearchProject.objects.create(topic=&quot;Swallow Aerodynamics&quot;, supervisor=&quot;Dr. Winter&quot;) &gt;&gt;&gt; ResearchProject.objects.create(topic=&quot;Swallow Aerodynamics&quot;, supervisor=&quot;Dr. Winter&quot;)
</pre> </pre>
</div> </div>
@ -278,7 +277,7 @@ class ResearchProject(Project):
<h2>Get polymorphic query results</h2> <h2>Get polymorphic query results</h2>
<pre class="doctest-block"> <pre class="doctest-block">
&gt;&gt;&gt; Project.objects.all() &gt;&gt;&gt; Project.objects.all()
[ &lt;Project: id 1, topic &quot;John's Gathering&quot;&gt;, [ &lt;Project: id 1, topic &quot;Department Party&quot;&gt;,
&lt;ArtProject: id 2, topic &quot;Painting with Tim&quot;, artist &quot;T. Turner&quot;&gt;, &lt;ArtProject: id 2, topic &quot;Painting with Tim&quot;, artist &quot;T. Turner&quot;&gt;,
&lt;ResearchProject: id 3, topic &quot;Swallow Aerodynamics&quot;, supervisor &quot;Dr. Winter&quot;&gt; ] &lt;ResearchProject: id 3, topic &quot;Swallow Aerodynamics&quot;, supervisor &quot;Dr. Winter&quot;&gt; ]
</pre> </pre>
@ -302,21 +301,27 @@ or supervisor (note the three underscores):</p>
<p>This is basically all you need to know, as django_polymorphic mostly <p>This is basically all you need to know, as django_polymorphic mostly
works fully automatic and just delivers the expected (&quot;pythonic&quot;) results.</p> works fully automatic and just delivers the expected (&quot;pythonic&quot;) results.</p>
<p>Note: In all example output, above and below, for a nicer and more informative <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> output the <tt class="docutils literal">ShowFieldType</tt> mixin has been used (documented below).</p>
</div> </div>
</div> </div>
<div class="section" id="list-of-features"> <div class="section" id="list-of-features">
<h1><a class="toc-backref" href="#id3">List of Features</a></h1> <h1><a class="toc-backref" href="#id3">List of Features</a></h1>
<ul class="simple"> <ul class="simple">
<li>Fully automatic; generally makes sure that the same objects are returned <li>Fully automatic - generally makes sure that the same objects are
from the database that were stored there, regardless how they are retrieved</li> returned from the database that were stored there, regardless how
they are retrieved</li>
<li>Only on models that request polymorphic behaviour however (and the
models inheriting from them)</li>
<li>Full support for ForeignKeys, ManyToManyFields and OneToToneFields</li> <li>Full support for ForeignKeys, ManyToManyFields and OneToToneFields</li>
<li>Filtering for classes, equivalent to python's isinstance(): instance_of(...), not_instance_of(...)</li> <li>Filtering for classes, equivalent to python's isinstance():
<li>Polymorphic filtering/ordering etc., allowing the use of fields of derived models (&quot;ArtProject___artist&quot;)</li> <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>
<li>Polymorphic filtering/ordering etc., allowing the use of fields of
derived models (&quot;ArtProject___artist&quot;)</li>
<li>Support for user-defined custom managers</li> <li>Support for user-defined custom managers</li>
<li>Automatic inheritance of custom managers</li> <li>Automatic inheritance of custom managers</li>
<li>Support for user-defined custom queryset classes</li> <li>Support for user-defined custom queryset classes</li>
<li>Non-polymorphic queries, if needed - with no other change in features/behaviour</li> <li>Non-polymorphic queries if needed, with no other change in
features/behaviour</li>
<li>Combining querysets of different types/models (&quot;qs3 = qs1 | qs2&quot;)</li> <li>Combining querysets of different types/models (&quot;qs3 = qs1 | qs2&quot;)</li>
<li>Nice/informative display of polymorphic queryset results</li> <li>Nice/informative display of polymorphic queryset results</li>
</ul> </ul>
@ -401,8 +406,8 @@ syntax: <tt class="docutils literal">exact model name + three _ + field name</tt
&lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ] &lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ]
</pre> </pre>
</div> </div>
<div class="section" id="combining-querysets-querysets-as-object-containers"> <div class="section" id="combining-querysets">
<h2>Combining Querysets / Querysets as &quot;Object Containers&quot;</h2> <h2>Combining Querysets</h2>
<p>Querysets could now be regarded as object containers that allow the <p>Querysets could now be regarded as object containers that allow the
aggregation of different object types, very similar to python aggregation of different object types, very similar to python
lists - as long as the objects are accessed through the manager of lists - as long as the objects are accessed through the manager of
@ -465,24 +470,23 @@ class MyModelWithThirdParty(MyBaseModel, ThirdPartyModel):
</div> </div>
<div class="section" id="non-polymorphic-queries"> <div class="section" id="non-polymorphic-queries">
<h2>Non-Polymorphic Queries</h2> <h2>Non-Polymorphic Queries</h2>
<pre class="doctest-block">
&gt;&gt;&gt; qs=ModelA.objects.non_polymorphic().all()
&gt;&gt;&gt; qs
.
[ &lt;ModelA: id 1, field1 (CharField)&gt;,
&lt;ModelA: id 2, field1 (CharField)&gt;,
&lt;ModelA: id 3, field1 (CharField)&gt; ]
</pre>
<p>If you insert <tt class="docutils literal">.non_polymorphic()</tt> anywhere into the query chain, then <p>If you insert <tt class="docutils literal">.non_polymorphic()</tt> anywhere into the query chain, then
django_polymorphic will simply leave out the final step of retrieving the django_polymorphic will simply leave out the final step of retrieving the
real objects, and the manager/queryset will return objects of the type of real objects, and the manager/queryset will return objects of the type of
the base class you used for the query, like vanilla Django would the base class you used for the query, like vanilla Django would
(<tt class="docutils literal">ModelA</tt> in this example).</p> (<tt class="docutils literal">ModelA</tt> in this example).</p>
<pre class="doctest-block">
&gt;&gt;&gt; qs=ModelA.objects.non_polymorphic().all()
&gt;&gt;&gt; qs
[ &lt;ModelA: id 1, field1 (CharField)&gt;,
&lt;ModelA: id 2, field1 (CharField)&gt;,
&lt;ModelA: id 3, field1 (CharField)&gt; ]
</pre>
<p>There are no other changes in the behaviour of the queryset. For example, <p>There are no other changes in the behaviour of the queryset. For example,
enhancements for <tt class="docutils literal">filter()</tt> or <tt class="docutils literal">instance_of()</tt> etc. still work as expected. enhancements for <tt class="docutils literal">filter()</tt> or <tt class="docutils literal">instance_of()</tt> etc. still work as expected.
If you do the final step yourself, you get the usual polymorphic result:</p> If you do the final step yourself, you get the usual polymorphic result:</p>
<pre class="doctest-block"> <pre class="doctest-block">
&gt;&gt;&gt; qs.get_real_instances() &gt;&gt;&gt; ModelA.objects.get_real_instances(qs)
[ &lt;ModelA: id 1, field1 (CharField)&gt;, [ &lt;ModelA: id 1, field1 (CharField)&gt;,
&lt;ModelB: id 2, field1 (CharField), field2 (CharField)&gt;, &lt;ModelB: id 2, field1 (CharField), field2 (CharField)&gt;,
&lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ] &lt;ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)&gt; ]
@ -554,12 +558,14 @@ class ModelA(ShowFieldType, PolymorphicModel):
<p>You may also use ShowFieldContent or ShowFieldTypeAndContent to display <p>You may also use ShowFieldContent or ShowFieldTypeAndContent to display
additional information when printing querysets (or converting them to text).</p> additional information when printing querysets (or converting them to text).</p>
<p>When showing field contents, they will be truncated to 20 characters. You can <p>When showing field contents, they will be truncated to 20 characters. You can
modify this behaviour by setting a class variable like this:</p> modify this behaviour by setting a class variable in your model like this:</p>
<pre class="literal-block"> <pre class="literal-block">
class ModelA(ShowFieldType, PolymorphicModel): class ModelA(ShowFieldType, PolymorphicModel):
polymorphic_showfield_max_field_width = 20 polymorphic_showfield_max_field_width = 20
... ...
</pre> </pre>
<p>Similarly, pre-V1.0 output formatting can be re-estated by using
<tt class="docutils literal">polymorphic_showfield_old_format = True</tt>.</p>
</div> </div>
</div> </div>
<div class="section" id="custom-managers-querysets-manager-inheritance"> <div class="section" id="custom-managers-querysets-manager-inheritance">
@ -649,11 +655,6 @@ class MyModel(PolymorphicModel):
<p>The current implementation is rather simple and does not use any <p>The current implementation is rather simple and does not use any
custom SQL or Django DB layer internals - it is purely based on the custom SQL or Django DB layer internals - it is purely based on the
standard Django ORM.</p> standard Django ORM.</p>
<p>The advantages are that the implementation naturally works on all
supported database management systems, and consists of rather
clean source code which can be easily understood and enhanced.</p>
<p>The disadvantage is that this approach can not deliver the optimum
performance as it introduces additional database queries.</p>
<p>Specifically, the query:</p> <p>Specifically, the query:</p>
<pre class="literal-block"> <pre class="literal-block">
result_objects = list( ModelA.objects.filter(...) ) result_objects = list( ModelA.objects.filter(...) )
@ -670,69 +671,27 @@ without a tool like django_polymorphic, this usually results in a variation of</
<pre class="literal-block"> <pre class="literal-block">
result_objects = [ o.get_real_instance() for o in BaseModel.objects.filter(...) ] result_objects = [ o.get_real_instance() for o in BaseModel.objects.filter(...) ]
</pre> </pre>
<p>which has exceptionally bad performance, as it introduces one additional <p>which has very bad performance, as it introduces one additional
SQL query for every object in the result which is not of class <tt class="docutils literal">BaseModel</tt>. SQL query for every object in the result which is not of class <tt class="docutils literal">BaseModel</tt>.</p>
Relative to this, the performance of the current django_polymorphic <p>Compared to these solutions, django_polymorphic has the advantage
implementation is very good.</p> that it only needs one sql request per <em>object type</em>, and not <em>per object</em>.</p>
<p>If your project however needs perfect performance and the current <div class="section" id="performance-problems-with-postgresql-mysql-and-sqlite3">
performance implications of django_polymorphic are not acceptable, then <span id="performance"></span><h2>Performance Problems with PostgreSQL, MySQL and SQLite3</h2>
basically there are the two options of either foregoing of an essential aspect <p>Current relational DBM systems seem to be have general problems with
of object oriented programming or optimizing django_polymorphic.</p> the SQL queries produced by object relational mappers like the Django
<p>Foregoing the benefits of this aspect of object oriented programming ORM, if these use multi-table inheritance like Django's ORM does.
for projects that could benefit from it will however usually lead to bloated code, The &quot;inner joins&quot; in these queries can perform very badly.
unnecessary complexity and considerably more of the programmer's time to This is independent of django_polymorphic and affects all uses of
create and update the implementation, together with the disadvantages multi table Model inheritance.</p>
of a less flexible and less future-proof solution. Throwing a little more <p>Concrete benchmark results are forthcoming (please see discussion forum).</p>
hardware on the problem might be the least expensive solution in most cases.</p> <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>
</div>
<div class="section" id="possible-optimizations">
<h1><a class="toc-backref" href="#id8">Possible Optimizations</a></h1>
<p>Django_polymorphic can be optimized to require only one
SQL query for the queryset evaluation and retrieval of all objects.</p>
<p>Probably all that would be needed seems support for an additional
queryset function in Django's database layer, like:</p>
<pre class="literal-block">
ModelA.objects.join_models(on=&quot;field_name&quot;, models=[ModelB, ModelC])
</pre>
<p>or, less general but more simple:</p>
<pre class="literal-block">
ModelA.objects.join_tables(on=&quot;field_name&quot;, tables=['tableB','tableC'])
</pre>
<p>This would add additional left outer joins to the query and then add
the resulting fields from this join to the result objects.
E.g. a query for <tt class="docutils literal">ModelA</tt> objects would need to join the <tt class="docutils literal">ModelB</tt>
and <tt class="docutils literal">ModelC</tt> tables on the the field <tt class="docutils literal">id</tt> and add the fields <tt class="docutils literal">field2</tt>
and <tt class="docutils literal">field3</tt> from the joined tables to the resulting objects.</p>
<p>An optimization like this 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).</p>
<p>With two SQL queries, the number of joins could be reduced to the
number of actuallly occurring subclasses in the specific result.</p>
<p>A perfect 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>
<p>It seems that further optimization (down to one DB request)
of django_polymorphic would be restricted to a relatively small area of
the code (&quot;query.py&quot;), and be pretty much independent from the rest of the module.
Such an optimization can be done at any later time (like when it's needed).</p>
</div> </div>
</div> </div>
<div class="section" id="restrictions-caveats"> <div class="section" id="restrictions-caveats">
<span id="restrictions"></span><h1><a class="toc-backref" href="#id9">Restrictions &amp; Caveats</a></h1> <span id="restrictions"></span><h1><a class="toc-backref" href="#id8">Restrictions &amp; Caveats</a></h1>
<ul class="simple"> <ul class="simple">
<li>Database Performance regarding concrete Model inheritance in general
Please see &quot;Performance Problems&quot; above.</li>
<li>Queryset methods <tt class="docutils literal">values()</tt>, <tt class="docutils literal">values_list()</tt>, <tt class="docutils literal">select_related()</tt>, <li>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). <tt class="docutils literal">defer()</tt> and <tt class="docutils literal">only()</tt> are not yet fully supported (see above).
<tt class="docutils literal">extra()</tt> has one restriction: the resulting objects are required to have <tt class="docutils literal">extra()</tt> has one restriction: the resulting objects are required to have
@ -772,13 +731,13 @@ use ContentType). This issue seems to be resolved for Django 1.2
</ul> </ul>
</div> </div>
<div class="section" id="project-status"> <div class="section" id="project-status">
<h1><a class="toc-backref" href="#id10">Project Status</a></h1> <h1><a class="toc-backref" href="#id9">Project Status</a></h1>
<p>Django_polymorphic works well for a considerable number of users now, <p>Django_polymorphic works well for a considerable number of users now,
and no major problems have shown up for many months. and no major problems have shown up for many months.
The API can be considered stable beginning with the V1.0 release.</p> The API can be considered stable beginning with the V1.0 release.</p>
</div> </div>
<div class="section" id="links"> <div class="section" id="links">
<h1><a class="toc-backref" href="#id11">Links</a></h1> <h1><a class="toc-backref" href="#id10">Links</a></h1>
<ul class="simple"> <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://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://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>

View File

@ -184,8 +184,8 @@ syntax: ``exact model name + three _ + field name``):
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ] <ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
Combining Querysets / Querysets as "Object Containers" Combining Querysets
------------------------------------------------------ -------------------
Querysets could now be regarded as object containers that allow the Querysets could now be regarded as object containers that allow the
aggregation of different object types, very similar to python aggregation of different object types, very similar to python
@ -446,7 +446,7 @@ instead of Django's QuerySet as the base class::
my_objects=PolymorphicManager(MyQuerySet) my_objects=PolymorphicManager(MyQuerySet)
... ...
Performance Considerations Performance Considerations
========================== ==========================
@ -454,13 +454,6 @@ The current implementation is rather simple and does not use any
custom SQL or Django DB layer internals - it is purely based on the custom SQL or Django DB layer internals - it is purely based on the
standard Django ORM. standard Django ORM.
The advantages are that the implementation naturally works on all
supported database management systems, and consists of rather
clean source code which can be easily understood and enhanced.
The disadvantage is that this approach can not deliver the optimum
performance as it introduces additional database queries.
Specifically, the query:: Specifically, the query::
result_objects = list( ModelA.objects.filter(...) ) result_objects = list( ModelA.objects.filter(...) )
@ -478,76 +471,29 @@ without a tool like django_polymorphic, this usually results in a variation of :
result_objects = [ o.get_real_instance() for o in BaseModel.objects.filter(...) ] result_objects = [ o.get_real_instance() for o in BaseModel.objects.filter(...) ]
which has exceptionally bad performance, as it introduces one additional which has very bad performance, as it introduces one additional
SQL query for every object in the result which is not of class ``BaseModel``. SQL query for every object in the result which is not of class ``BaseModel``.
Relative to this, the performance of the current django_polymorphic
implementation is very good.
If your project however needs perfect performance and the current Compared to these solutions, django_polymorphic has the advantage
performance implications of django_polymorphic are not acceptable, then that it only needs one sql request per *object type*, and not *per object*.
basically there are the two options of either foregoing of an essential aspect
of object oriented programming or optimizing django_polymorphic.
Foregoing the benefits of this aspect of object oriented programming .. _performance:
for projects that could benefit from it will however usually lead to bloated code,
unnecessary complexity and considerably more of the programmer's time to
create and update the implementation, together with the disadvantages
of a less flexible and less future-proof solution. Throwing a little more
hardware on the problem might be the least expensive solution in most cases.
Performance Problems with PostgreSQL, MySQL and SQLite3
-------------------------------------------------------
Possible Optimizations Current relational DBM systems seem to be have general problems with
====================== the SQL queries produced by object relational mappers like the Django
ORM, if these use multi-table inheritance like Django's ORM does.
The "inner joins" in these queries can perform very badly.
This is independent of django_polymorphic and affects all uses of
multi table Model inheritance.
Django_polymorphic can be optimized to require only one Concrete benchmark results are forthcoming (please see discussion forum).
SQL query for the queryset evaluation and retrieval of all objects.
Probably all that would be needed seems support for an additional Please also see this `post (and comments) from Jacob Kaplan-Moss`_.
queryset function in Django's database layer, like::
ModelA.objects.join_models(on="field_name", models=[ModelB, ModelC]) .. _post (and comments) from Jacob Kaplan-Moss: http://www.jacobian.org/writing/concrete-inheritance/
or, less general but more simple::
ModelA.objects.join_tables(on="field_name", tables=['myapp_modelb','myapp_modelc'])
This would add additional left outer joins to the query and then add
the resulting fields from this join to the result objects.
E.g. a query for ``ModelA`` objects would need to join the ``ModelB``
and ``ModelC`` tables on the the field ``id`` and add the fields ``field2``
and ``field3`` from the joined tables to the resulting objects.
An optimization like this might require an SQL database.
For non-SQL databases the implementation could fall back to
the current ORM-only implementation.
SQL Complexity of an Optimized Implementation
---------------------------------------------
With only one SQL query, one SQL join for each possible subclass
would be needed (``BaseModel.__subclasses__()``, recursively).
With two SQL queries, the number of joins could be reduced to the
number of actuallly occurring subclasses in the specific result.
A perfect 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).
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.
It seems that further optimization (down to one DB request)
of django_polymorphic would be restricted to a relatively small area of
the code ("query.py"), and be pretty much independent from the rest of the module.
Such an optimization can be done at any later time (like when it's needed).
.. _restrictions: .. _restrictions:
@ -555,6 +501,9 @@ Such an optimization can be done at any later time (like when it's needed).
Restrictions & Caveats Restrictions & Caveats
====================== ======================
* Database Performance regarding concrete Model inheritance in general
Please see "Performance Problems" above.
* Queryset methods ``values()``, ``values_list()``, ``select_related()``, * Queryset methods ``values()``, ``values_list()``, ``select_related()``,
``defer()`` and ``only()`` are not yet fully supported (see above). ``defer()`` and ``only()`` are not yet fully supported (see above).
``extra()`` has one restriction: the resulting objects are required to have ``extra()`` has one restriction: the resulting objects are required to have

View File

@ -229,23 +229,16 @@ ul.auto-toc {
<li><a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html#quickstart">Quickstart</a>, or the complete <a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html">Installation and Usage Docs</a></li> <li><a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html#quickstart">Quickstart</a>, or the complete <a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html">Installation and Usage Docs</a></li>
<li><a class="reference external" href="http://groups.google.de/group/django-polymorphic/topics">Release Notes, News and Discussion</a> (Google Group) or <a class="reference external" href="http://bserve.webhop.org/django_polymorphic/CHANGES.html">Changelog</a></li> <li><a class="reference external" href="http://groups.google.de/group/django-polymorphic/topics">Release Notes, News and Discussion</a> (Google Group) or <a class="reference external" href="http://bserve.webhop.org/django_polymorphic/CHANGES.html">Changelog</a></li>
<li>Download from <a class="reference external" href="http://github.com/bconstantin/django_polymorphic">GitHub</a> or <a class="reference external" href="http://bitbucket.org/bconstantin/django_polymorphic">Bitbucket</a>, or as <a class="reference external" href="http://github.com/bconstantin/django_polymorphic/tarball/master">TGZ</a> or <a class="reference external" href="http://github.com/bconstantin/django_polymorphic/zipball/master">ZIP</a></li> <li>Download from <a class="reference external" href="http://github.com/bconstantin/django_polymorphic">GitHub</a> or <a class="reference external" href="http://bitbucket.org/bconstantin/django_polymorphic">Bitbucket</a>, or as <a class="reference external" href="http://github.com/bconstantin/django_polymorphic/tarball/master">TGZ</a> or <a class="reference external" href="http://github.com/bconstantin/django_polymorphic/zipball/master">ZIP</a></li>
<li>Improve django_polymorphic, report issues, participate, discuss, patch or fork (<a class="reference external" href="http://github.com/bconstantin/django_polymorphic">GitHub</a>, <a class="reference external" href="http://bitbucket.org/bconstantin/django_polymorphic">Bitbucket</a>, <a class="reference external" href="http://groups.google.de/group/django-polymorphic/topics">Group</a>, <a class="reference external" href="http://github.com/bconstantin/django_polymorphic/tree/master/setup.py">Mail</a>)</li> <li>Improve django_polymorphic, report issues, discuss, patch or fork (<a class="reference external" href="http://github.com/bconstantin/django_polymorphic">GitHub</a>, <a class="reference external" href="http://bitbucket.org/bconstantin/django_polymorphic">Bitbucket</a>, <a class="reference external" href="http://groups.google.de/group/django-polymorphic/topics">Group</a>, <a class="reference external" href="http://github.com/bconstantin/django_polymorphic/tree/master/setup.py">Mail</a>)</li>
</ul> </ul>
</div> </div>
<div class="section" id="id1"> <div class="section" id="id1">
<span id="good-for"></span><h2>What is django_polymorphic good for?</h2> <span id="good-for"></span><h2>What is django_polymorphic good for?</h2>
<p>If you work with Django's model inheritance, django_polymorphic might
save you from implementing unpleasant workarounds that make your code
messy, error-prone, and slow. Model inheritance becomes much more &quot;pythonic&quot;
and now just works as you as a Python programmer expect.</p>
</div>
<div class="section" id="it-s-best-to-look-at-an-example">
<h2>It's best to Look at an Example</h2>
<p>Let's assume the models <tt class="docutils literal">ArtProject</tt> and <tt class="docutils literal">ResearchProject</tt> are derived <p>Let's assume the models <tt class="docutils literal">ArtProject</tt> and <tt class="docutils literal">ResearchProject</tt> are derived
from the model <tt class="docutils literal">Project</tt>, and let's store one of each into the database:</p> from the model <tt class="docutils literal">Project</tt>, and let's store one of each into the database:</p>
<pre class="doctest-block"> <pre class="doctest-block">
&gt;&gt;&gt; Project.objects.create(topic=&quot;John's Gathering&quot;) &gt;&gt;&gt; Project.objects.create(topic=&quot;Department Party&quot;)
&gt;&gt;&gt; ArtProject.objects.create(topic=&quot;Sculpting with Tim&quot;, artist=&quot;T. Turner&quot;) &gt;&gt;&gt; ArtProject.objects.create(topic=&quot;Painting with Tim&quot;, artist=&quot;T. Turner&quot;)
&gt;&gt;&gt; ResearchProject.objects.create(topic=&quot;Swallow Aerodynamics&quot;, supervisor=&quot;Dr. Winter&quot;) &gt;&gt;&gt; ResearchProject.objects.create(topic=&quot;Swallow Aerodynamics&quot;, supervisor=&quot;Dr. Winter&quot;)
</pre> </pre>
<p>If we want to retrieve all our projects, we do:</p> <p>If we want to retrieve all our projects, we do:</p>
@ -254,32 +247,39 @@ from the model <tt class="docutils literal">Project</tt>, and let's store one of
</pre> </pre>
<p>Using django_polymorphic, we simply get what we stored:</p> <p>Using django_polymorphic, we simply get what we stored:</p>
<pre class="literal-block"> <pre class="literal-block">
[ &lt;Project: id 1, topic &quot;John's Gathering&quot;&gt;, [ &lt;Project: id 1, topic &quot;Department Party&quot;&gt;,
&lt;ArtProject: id 2, topic &quot;Painting with Tim&quot;, artist &quot;T. Turner&quot;&gt;, &lt;ArtProject: id 2, topic &quot;Painting with Tim&quot;, artist &quot;T. Turner&quot;&gt;,
&lt;ResearchProject: id 3, topic &quot;Swallow Aerodynamics&quot;, supervisor &quot;Dr. Winter&quot;&gt; ] &lt;ResearchProject: id 3, topic &quot;Swallow Aerodynamics&quot;, supervisor &quot;Dr. Winter&quot;&gt; ]
</pre> </pre>
<p>Using vanilla Django, we get incomplete objects, which is probably not what we wanted:</p> <p>Using vanilla Django, we get incomplete objects, which is probably not what we wanted:</p>
<pre class="literal-block"> <pre class="literal-block">
[ &lt;Project: id 1, topic &quot;John's Gathering&quot;&gt;, [ &lt;Project: id 1, topic &quot;Department Party&quot;&gt;,
&lt;Project: id 2, topic &quot;Painting with Tim&quot;&gt;, &lt;Project: id 2, topic &quot;Painting with Tim&quot;&gt;,
&lt;Project: id 3, topic &quot;Swallow Aerodynamics&quot;&gt; ] &lt;Project: id 3, topic &quot;Swallow Aerodynamics&quot;&gt; ]
</pre> </pre>
<p>It's very similar for ForeignKeys, ManyToManyFields or OneToOneFields.</p> <p>It's very similar for ForeignKeys, ManyToManyFields or OneToOneFields.</p>
<p>In general, the effect of django_polymorphic is twofold:</p> <p>In general, the effect of django_polymorphic is twofold:</p>
<p>On one hand it makes sure that model inheritance just works <p>On one hand it makes sure that model inheritance just works as you
as you expect, by simply ensuring that you always get back exactly the same expect, by simply ensuring that you always get back exactly the same
objects from the database you stored there - regardless how you access them. objects from the database you stored there - regardless how you access
This can save you a lot of unpleasant workarounds.</p> them, making model inheritance much more &quot;pythonic&quot;.
<p>On the other hand, together with a few small API additions to the Django ORM, This can save you a lot of unpleasant workarounds that tend to
django_polymorphic enables a much more expressive and intuitive make your code messy, error-prone, and slow.</p>
programming style and also very advanced object oriented <p>On the other hand, together with some small API additions to the Django
designs that are not possible with vanilla Django.</p> ORM, django_polymorphic enables a much more expressive and intuitive
programming style and also very advanced object oriented designs
that are not possible with vanilla Django.</p>
<p>Fortunately, most of the heavy duty machinery that is needed for this <p>Fortunately, most of the heavy duty machinery that is needed for this
functionality is already present in the original Django database layer. functionality is already present in the original Django database layer.
Django_polymorphic adds a rather small layer above that, which is Django_polymorphic adds a rather thin layer above that in order
all that is required to make real OO fully automatic and very easy to use.</p> to make real OO fully automatic and very easy to use.</p>
<p>For more information, please look at <a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html#quickstart">Quickstart</a> or the complete <p>There is a catch however, which applies to concrete model inheritance
<a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html">Installation and Usage Docs</a>. Please also see the <a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html#restrictions">restrictions and caveats</a>.</p> in general: Current DBM systems like PostgreSQL or MySQL are not very
good at processing the required sql queries and can be rather slow in
many cases. Concrete benchmarks are forthcoming (please see
discussion forum).</p>
<p>For more information, please look at <a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html#quickstart">Quickstart</a> or at the complete
<a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html">Installation and Usage Docs</a> and also see the <a class="reference external" href="http://bserve.webhop.org/django_polymorphic/DOCS.html#restrictions">restrictions and caveats</a>.</p>
</div> </div>
<div class="section" id="this-is-a-v1-0-beta-testing-release"> <div class="section" id="this-is-a-v1-0-beta-testing-release">
<h2>This is a V1.0 Beta/Testing Release</h2> <h2>This is a V1.0 Beta/Testing Release</h2>
@ -299,22 +299,23 @@ or open an issue on <a class="reference external" href="http://github.com/bconst
</div> </div>
<div class="section" id="api-changes-additions"> <div class="section" id="api-changes-additions">
<h1>API Changes &amp; Additions</h1> <h1>API Changes &amp; Additions</h1>
<div class="section" id="october-26-2010-v1-0-api-changes"> <div class="section" id="november-11-2010-v1-0-api-changes">
<h2>October 26 2010, V1.0 API Changes</h2> <h2>November 11 2010, V1.0 API Changes</h2>
<div class="section" id="extra-queryset-method"> <div class="section" id="extra-queryset-method">
<h3>extra() queryset method</h3> <h3>extra() queryset method</h3>
<p><tt class="docutils literal">.extra()</tt> has been re-implemented. Now it's polymorphic by <p><tt class="docutils literal">.extra()</tt> has been re-implemented. Now it's polymorphic by
default and works (nearly) without restrictions (please see docs). This is an default and works (nearly) without restrictions (please see docs). This is a (very)
incompatible API change regarding previous versions of django_polymorphic. incompatible API change regarding previous versions of django_polymorphic.
Support for the <tt class="docutils literal">polymorphic</tt> keyword parameter has been removed. Support for the <tt class="docutils literal">polymorphic</tt> keyword parameter has been removed.
You can get back the non-polymorphic behaviour by using You can get back the non-polymorphic behaviour by using
<tt class="docutils literal"><span class="pre">ModelA.objects.non_polymorphic().extra()</span></tt>.</p> <tt class="docutils literal"><span class="pre">ModelA.objects.non_polymorphic().extra()</span></tt>.</p>
</div> </div>
<div class="section" id="output-of-queryset-or-object-printing"> <div class="section" id="no-pretty-printing-of-querysets-by-default">
<h3>Output of Queryset or Object Printing</h3> <h3>No Pretty-Printing of Querysets by default</h3>
<p>In order to improve compatibility with vanilla Django, printing quersets does not use <p>In order to improve compatibility with vanilla Django, printing quersets
django_polymorphic's pretty printing by default anymore. (__repr__ and __unicode__) does not use django_polymorphic's pretty printing
To get the old behaviour when printing querysets, you need to replace your model definition:</p> by default anymore. To get the old behaviour when printing querysets,
you need to replace your model definition:</p>
<pre class="doctest-block"> <pre class="doctest-block">
&gt;&gt;&gt; class Project(PolymorphicModel): &gt;&gt;&gt; class Project(PolymorphicModel):
</pre> </pre>
@ -330,6 +331,15 @@ To get the old behaviour when printing querysets, you need to replace your model
<tt class="docutils literal">ShowFieldType, ShowFieldContent and ShowFieldTypeAndContent</tt></blockquote> <tt class="docutils literal">ShowFieldType, ShowFieldContent and ShowFieldTypeAndContent</tt></blockquote>
<p>(the old ones still exist for compatibility)</p> <p>(the old ones still exist for compatibility)</p>
</div> </div>
<div class="section" id="pretty-printing-output-format-changed">
<h3>Pretty-Printing Output Format Changed</h3>
<p><tt class="docutils literal">ShowFieldContent</tt> and <tt class="docutils literal">ShowFieldTypeAndContent</tt> now
use a slightly different output format. If this causes too much trouble for
your test cases, you can get the old behaviour back (mostly) by adding
<tt class="docutils literal">polymorphic_showfield_old_format = True</tt> to your model definitions.
<tt class="docutils literal"><span class="pre">ShowField...</span></tt> now also produces more informative output for custom
primary keys.</p>
</div>
<div class="section" id="polymorphic-dumpdata"> <div class="section" id="polymorphic-dumpdata">
<h3>polymorphic_dumpdata</h3> <h3>polymorphic_dumpdata</h3>
<p>The <tt class="docutils literal">polymorphic_dumpdata</tt> management command is not needed anymore <p>The <tt class="docutils literal">polymorphic_dumpdata</tt> management command is not needed anymore
@ -342,8 +352,8 @@ works correctly with polymorphic models (for all supported versions of Django).<
just <tt class="docutils literal">python manage.py test</tt>.</p> just <tt class="docutils literal">python manage.py test</tt>.</p>
</div> </div>
</div> </div>
<div class="section" id="october-26-2010-v1-0-api-additions"> <div class="section" id="november-01-2010-v1-0-api-additions">
<h2>October 26 2010, V1.0 API Additions</h2> <h2>November 01 2010, V1.0 API Additions</h2>
<ul> <ul>
<li><p class="first"><tt class="docutils literal">.non_polymorphic()</tt> queryset member function added. This is preferable to <li><p class="first"><tt class="docutils literal">.non_polymorphic()</tt> queryset member function added. This is preferable to
using <tt class="docutils literal"><span class="pre">.base_objects...</span></tt>, as it just makes the resulting queryset non-polymorphic using <tt class="docutils literal"><span class="pre">.base_objects...</span></tt>, as it just makes the resulting queryset non-polymorphic

View File

@ -9,7 +9,7 @@ Quick Start, Docs, Contributing
* `Quickstart`_, or the complete `Installation and Usage Docs`_ * `Quickstart`_, or the complete `Installation and Usage Docs`_
* `Release Notes, News and Discussion`_ (Google Group) or Changelog_ * `Release Notes, News and Discussion`_ (Google Group) or Changelog_
* Download from GitHub_ or Bitbucket_, or as TGZ_ or ZIP_ * Download from GitHub_ or Bitbucket_, or as TGZ_ or ZIP_
* Improve django_polymorphic, report issues, participate, discuss, patch or fork (GitHub_, Bitbucket_, Group_, Mail_) * Improve django_polymorphic, report issues, discuss, patch or fork (GitHub_, Bitbucket_, Group_, Mail_)
.. _What is django_polymorphic good for?: #good-for .. _What is django_polymorphic good for?: #good-for
.. _release notes, news and discussion: http://groups.google.de/group/django-polymorphic/topics .. _release notes, news and discussion: http://groups.google.de/group/django-polymorphic/topics
@ -32,8 +32,8 @@ What is django_polymorphic good for?
Let's assume the models ``ArtProject`` and ``ResearchProject`` are derived Let's assume the models ``ArtProject`` and ``ResearchProject`` are derived
from the model ``Project``, and let's store one of each into the database: from the model ``Project``, and let's store one of each into the database:
>>> Project.objects.create(topic="John's Gathering") >>> Project.objects.create(topic="Department Party")
>>> ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner") >>> ArtProject.objects.create(topic="Painting with Tim", artist="T. Turner")
>>> ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter") >>> ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
If we want to retrieve all our projects, we do: If we want to retrieve all our projects, we do:
@ -57,7 +57,7 @@ It's very similar for ForeignKeys, ManyToManyFields or OneToOneFields.
In general, the effect of django_polymorphic is twofold: In general, the effect of django_polymorphic is twofold:
On one hand it makes sure that model inheritance just works as you On one hand it makes sure that model inheritance just works as you
expect, by simply ensuring that you always get back exactly thesame expect, by simply ensuring that you always get back exactly the same
objects from the database you stored there - regardless how you access objects from the database you stored there - regardless how you access
them, making model inheritance much more "pythonic". them, making model inheritance much more "pythonic".
This can save you a lot of unpleasant workarounds that tend to This can save you a lot of unpleasant workarounds that tend to
@ -70,11 +70,17 @@ that are not possible with vanilla Django.
Fortunately, most of the heavy duty machinery that is needed for this Fortunately, most of the heavy duty machinery that is needed for this
functionality is already present in the original Django database layer. functionality is already present in the original Django database layer.
Django_polymorphic adds a rather thin layer above that, which is Django_polymorphic adds a rather thin layer above that in order
all that is required to make real OO fully automatic and very easy to use. to make real OO fully automatic and very easy to use.
There is a catch however, which applies to concrete model inheritance
in general: Current DBM systems like PostgreSQL or MySQL are not very
good at processing the required sql queries and can be rather slow in
many cases. Concrete benchmarks are forthcoming (please see
discussion forum).
For more information, please look at `Quickstart`_ or at the complete For more information, please look at `Quickstart`_ or at the complete
`Installation and Usage Docs`_.Please also see the `restrictions and caveats`_. `Installation and Usage Docs`_ and also see the `restrictions and caveats`_.
.. _restrictions and caveats: http://bserve.webhop.org/django_polymorphic/DOCS.html#restrictions .. _restrictions and caveats: http://bserve.webhop.org/django_polymorphic/DOCS.html#restrictions
@ -105,14 +111,14 @@ API Changes & Additions
======================= =======================
November 01 2010, V1.0 API Changes November 11 2010, V1.0 API Changes
------------------------------------------------------------------- -------------------------------------------------------------------
extra() queryset method extra() queryset method
+++++++++++++++++++++++ +++++++++++++++++++++++
``.extra()`` has been re-implemented. Now it's polymorphic by ``.extra()`` has been re-implemented. Now it's polymorphic by
default and works (nearly) without restrictions (please see docs). This is an default and works (nearly) without restrictions (please see docs). This is a (very)
incompatible API change regarding previous versions of django_polymorphic. incompatible API change regarding previous versions of django_polymorphic.
Support for the ``polymorphic`` keyword parameter has been removed. Support for the ``polymorphic`` keyword parameter has been removed.
You can get back the non-polymorphic behaviour by using You can get back the non-polymorphic behaviour by using
@ -121,9 +127,10 @@ You can get back the non-polymorphic behaviour by using
No Pretty-Printing of Querysets by default No Pretty-Printing of Querysets by default
++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++
In order to improve compatibility with vanilla Django, printing quersets does not use In order to improve compatibility with vanilla Django, printing quersets
django_polymorphic's pretty printing by default anymore. (__repr__ and __unicode__) does not use django_polymorphic's pretty printing
To get the old behaviour when printing querysets, you need to replace your model definition: by default anymore. To get the old behaviour when printing querysets,
you need to replace your model definition:
>>> class Project(PolymorphicModel): >>> class Project(PolymorphicModel):
@ -148,7 +155,7 @@ Pretty-Printing Output Format Changed
use a slightly different output format. If this causes too much trouble for use a slightly different output format. If this causes too much trouble for
your test cases, you can get the old behaviour back (mostly) by adding your test cases, you can get the old behaviour back (mostly) by adding
``polymorphic_showfield_old_format = True`` to your model definitions. ``polymorphic_showfield_old_format = True`` to your model definitions.
``ShowField...`` also produces more informative output for custom ``ShowField...`` now also produces more informative output for custom
primary keys. primary keys.
polymorphic_dumpdata polymorphic_dumpdata

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
This module is a scratchpad for general development, testing & debugging This module is a scratchpad for general development, testing & debugging
Well, even more so than pcmd.py. You best ignore p2cmd.py.
""" """
import uuid import uuid
@ -8,6 +9,7 @@ from django.core.management.base import NoArgsCommand
from django.db.models import connection from django.db.models import connection
from pprint import pprint from pprint import pprint
import settings import settings
import time,sys
from pexp.models import * from pexp.models import *
@ -17,6 +19,27 @@ def reset_queries():
def show_queries(): def show_queries():
print; print 'QUERIES:',len(connection.queries); pprint(connection.queries); print; connection.queries=[] print; print 'QUERIES:',len(connection.queries); pprint(connection.queries); print; connection.queries=[]
def print_timing(func, message='', iterations=1):
def wrapper(*arg):
results=[]
reset_queries()
for i in xrange(iterations):
t1 = time.time()
x = func(*arg)
t2 = time.time()
results.append((t2-t1)*1000.0)
res_sum=0
for r in results: res_sum +=r
median = res_sum / len(results)
print '%s%-19s: %.4f ms, %i queries (%i times)' % (
message,func.func_name,
res_sum,
len(connection.queries),
iterations
)
sys.stdout.flush()
return wrapper
class Command(NoArgsCommand): class Command(NoArgsCommand):
help = "" help = ""
@ -24,27 +47,64 @@ class Command(NoArgsCommand):
print 'polycmd - sqlite test db is stored in:',settings.SQLITE_DB_PATH print 'polycmd - sqlite test db is stored in:',settings.SQLITE_DB_PATH
print print
Project.objects.all().delete() if False:
a=Project.objects.create(topic="John's gathering") ModelA.objects.all().delete()
b=ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner") a=ModelA.objects.create(field1='A1')
c=ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter") b=ModelB.objects.create(field1='B1', field2='B2')
print Project.objects.all() c=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
print reset_queries()
print ModelC.base_objects.all();
show_queries()
ModelA.objects.all().delete() if False:
a=ModelA.objects.create(field1='A1') ModelA.objects.all().delete()
b=ModelB.objects.create(field1='B1', field2='B2') for i in xrange(1000):
c=ModelC.objects.create(field1='C1', field2='C2', field3='C3') a=ModelA.objects.create(field1=str(i%100))
<<<<<<< HEAD:pexp/management/commands/p2cmd.py b=ModelB.objects.create(field1=str(i%100), field2=str(i%200))
print ModelA.objects.extra( select={"select1": "field1 = 'A1'", "select2": "field1 = 'A0'"} ) c=ModelC.objects.create(field1=str(i%100), field2=str(i%200), field3=str(i%300))
======= if i%100==0: print i
print ModelA.objects.extra( select={"select1": "field1 = 'A1'", "select2": "field1 != 'A1'"} )
>>>>>>> 7c2be35... pexp:pexp/management/commands/p2cmd.py
print
if not 'UUIDField' in globals(): return f=print_timing(poly_sql_query,iterations=1000)
UUIDModelA.objects.all().delete() f()
a=UUIDModelA.objects.create(field1='012345678900123456789001234567890012345678900123456789001234567890')
b=UUIDModelB.objects.create(field1='B1', field2='B2') f=print_timing(poly_sql_query2,iterations=1000)
c=UUIDModelC.objects.create(field1='C1', field2='C2', field3='C3') f()
print UUIDModelA.objects.all()
return
nModelA.objects.all().delete()
a=nModelA.objects.create(field1='A1')
b=nModelB.objects.create(field1='B1', field2='B2')
c=nModelC.objects.create(field1='C1', field2='C2', field3='C3')
qs=ModelA.objects.raw("SELECT * from pexp_modela")
for o in list(qs): print o
from django.db import connection, transaction
from random import Random
rnd=Random()
def poly_sql_query():
cursor = connection.cursor()
cursor.execute("""
SELECT id, pexp_modela.field1, pexp_modelb.field2, pexp_modelc.field3
FROM pexp_modela
LEFT OUTER JOIN pexp_modelb
ON pexp_modela.id = pexp_modelb.modela_ptr_id
LEFT OUTER JOIN pexp_modelc
ON pexp_modelb.modela_ptr_id = pexp_modelc.modelb_ptr_id
WHERE pexp_modela.field1=%i
ORDER BY pexp_modela.id
""" % rnd.randint(0,100) )
#row=cursor.fetchone()
return
def poly_sql_query2():
cursor = connection.cursor()
cursor.execute("""
SELECT id, pexp_modela.field1
FROM pexp_modela
WHERE pexp_modela.field1=%i
ORDER BY pexp_modela.id
""" % rnd.randint(0,100) )
#row=cursor.fetchone()
return

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" """
This module is a scratchpad for general development, testing & debugging This module is a scratchpad for general development, testing & debugging.
""" """
from django.core.management.base import NoArgsCommand from django.core.management.base import NoArgsCommand