Skip to content

Commit

Permalink
translate_polymorphic_Q_object: fixed test case, and made the functio…
Browse files Browse the repository at this point in the history
…n a member of PolymorphicObject.

Minor test fixes: warnings fixed, test_tool.py renamed as it's no test
  • Loading branch information
bconstantin committed Nov 12, 2010
1 parent ca329ff commit 4a4cfd8
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 41 deletions.
3 changes: 3 additions & 0 deletions CHANGES.html
Expand Up @@ -276,6 +276,9 @@ <h3>New Features and API changes in Beta 2 since Beta 1</h3>
&gt;&gt;&gt; ModelA.objects.all()
</pre>
</li>
<li><p class="first">added member function:
<tt class="docutils literal">normal_q_object = ModelA.translate_polymorphic_Q_object(enhanced_q_object)</tt></p>
</li>
<li><p class="first">misc changes/improvements</p>
</li>
</ul>
Expand Down
3 changes: 3 additions & 0 deletions CHANGES.rst
Expand Up @@ -60,6 +60,9 @@ New Features and API changes in Beta 2 since Beta 1

>>> ModelA.objects.all()

* added member function:
``normal_q_object = ModelA.translate_polymorphic_Q_object(enhanced_q_object)``

* misc changes/improvements

Bugfixes
Expand Down
32 changes: 13 additions & 19 deletions DOCS.html
Expand Up @@ -310,7 +310,7 @@ <h1><a class="toc-backref" href="#id3">List of Features</a></h1>
<li>Fully automatic - generally makes sure that the same objects are
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
<li>Only on models that request polymorphic behaviour (and the
models inheriting from them)</li>
<li>Full support for ForeignKeys, ManyToManyFields and OneToToneFields</li>
<li>Filtering for classes, equivalent to python's isinstance():
Expand Down Expand Up @@ -527,23 +527,17 @@ <h2>About Queryset Methods</h2>
</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>
<p>The queryset enhancements (e.g. <tt class="docutils literal">instance_of</tt>) only work as arguments
to the member functions of a polymorphic queryset. Occationally it may
be useful to be able to use Q objects with these enhancements in other places.
As Django doesn't understand these enhanced Q objects, you need to
transform them manually into normal Q objects before you can feed them
to a Django queryset or function:</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) ) )
normal_q_object = ModelA.translate_polymorphic_Q_object( Q(instance_of=Model2B) )
</pre>
<p>This function cannot be used at model creation time however (in models.py),
as it may need to access the ContentTypes database table.</p>
</div>
<div class="section" id="nicely-displaying-polymorphic-querysets">
<h2>Nicely Displaying Polymorphic Querysets</h2>
Expand Down Expand Up @@ -677,7 +671,7 @@ <h1><a class="toc-backref" href="#id7">Performance Considerations</a></h1>
that it only needs one sql request per <em>object type</em>, and not <em>per object</em>.</p>
<div class="section" id="performance-problems-with-postgresql-mysql-and-sqlite3">
<span id="performance"></span><h2>Performance Problems with PostgreSQL, MySQL and SQLite3</h2>
<p>Current relational DBM systems seem to be have general problems with
<p>Current relational DBM systems seem to 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 &quot;inner joins&quot; in these queries can perform very badly.
Expand All @@ -690,12 +684,12 @@ <h1><a class="toc-backref" href="#id7">Performance Considerations</a></h1>
<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>Database Performance regarding concrete Model inheritance in general
<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>,
<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
a unique primary key within the result set</li>
a unique primary key within the result set.</li>
<li>Django Admin Integration: There currently is no specific admin integration,
but it would most likely make sense to have one.</li>
<li>Diamond shaped inheritance: There seems to be a general problem
Expand Down
31 changes: 13 additions & 18 deletions DOCS.rst
Expand Up @@ -78,7 +78,7 @@ List of Features
* Fully automatic - generally makes sure that the same objects are
returned from the database that were stored there, regardless how
they are retrieved
* Only on models that request polymorphic behaviour however (and the
* Only on models that request polymorphic behaviour (and the
models inheriting from them)
* Full support for ForeignKeys, ManyToManyFields and OneToToneFields
* Filtering for classes, equivalent to python's isinstance():
Expand Down Expand Up @@ -319,22 +319,17 @@ About Queryset Methods
Using enhanced Q-objects in any Places
--------------------------------------

Sometimes it would be nice to be able to use the enhanced filter-definitions/Q-objects
outside of polymorphic models/querysets. Example (using ``limit_choices_to``
to filter the selection of objects in the admin)::
The queryset enhancements (e.g. ``instance_of``) only work as arguments
to the member functions of a polymorphic queryset. Occationally it may
be useful to be able to use Q objects with these enhancements in other places.
As Django doesn't understand these enhanced Q objects, you need to
transform them manually into normal Q objects before you can feed them
to a Django queryset or function::

class MyModel(models.Model):
somekey = model.ForeignKey(Model2A,
limit_choices_to = Q(instance_of=Model2B) )
normal_q_object = ModelA.translate_polymorphic_Q_object( Q(instance_of=Model2B) )

``instance_of`` is a django_polymorphic-specific enhancement of Q objects, which the
vanilla django function ``ForeignKey`` cannot process. In such cases you can do::

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) ) )
This function cannot be used at model creation time however (in models.py),
as it may need to access the ContentTypes database table.


Nicely Displaying Polymorphic Querysets
Expand Down Expand Up @@ -482,7 +477,7 @@ that it only needs one sql request per *object type*, and not *per object*.
Performance Problems with PostgreSQL, MySQL and SQLite3
-------------------------------------------------------

Current relational DBM systems seem to be have general problems with
Current relational DBM systems seem to 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.
Expand All @@ -501,13 +496,13 @@ Please also see this `post (and comments) from Jacob Kaplan-Moss`_.
Restrictions & Caveats
======================

* Database Performance regarding concrete Model inheritance in general
* Database Performance regarding concrete Model inheritance in general.
Please see "Performance Problems" above.

* Queryset methods ``values()``, ``values_list()``, ``select_related()``,
``defer()`` and ``only()`` are not yet fully supported (see above).
``extra()`` has one restriction: the resulting objects are required to have
a unique primary key within the result set
a unique primary key within the result set.

* Django Admin Integration: There currently is no specific admin integration,
but it would most likely make sense to have one.
Expand Down
5 changes: 5 additions & 0 deletions polymorphic/polymorphic_model.py
Expand Up @@ -27,6 +27,7 @@
from manager import PolymorphicManager
from query import PolymorphicQuerySet
from showfields import ShowFieldType
from query_translate import translate_polymorphic_Q_object


###################################################################################
Expand Down Expand Up @@ -76,6 +77,10 @@ class Meta:
objects = PolymorphicManager()
base_objects = models.Manager()

@classmethod
def translate_polymorphic_Q_object(self_class,q):
return translate_polymorphic_Q_object(self_class,q)

def pre_save_polymorphic(self):
"""Normally not needed.
This function may be called manually in special use-cases. When the object
Expand Down
10 changes: 8 additions & 2 deletions polymorphic/tests.py
Expand Up @@ -141,7 +141,7 @@ class BlogEntry(ShowFieldTypeAndContent, PolymorphicModel):
text = models.CharField(max_length=10)

class BlogEntry_limit_choices_to(ShowFieldTypeAndContent, PolymorphicModel):
blog = models.ForeignKey(BlogBase, limit_choices_to=translate_polymorphic_Q_object(BlogBase, Q(instance_of=BlogA) ) )
blog = models.ForeignKey(BlogBase)
text = models.CharField(max_length=10)

class ModelFieldNameTest(ShowFieldType, PolymorphicModel):
Expand All @@ -159,7 +159,7 @@ def x(self):

# UUID tests won't work with Django 1.1
if not (django_VERSION[0] <= 1 and django_VERSION[1] <= 1):
try: from polymorphic.test_tools import UUIDField
try: from polymorphic.tools_for_tests import UUIDField
except: pass
if 'UUIDField' in globals():
import uuid
Expand Down Expand Up @@ -369,6 +369,12 @@ def show_base_manager(model):
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>,
<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)> ]
# translate_polymorphic_Q_object
>>> q=Model2A.translate_polymorphic_Q_object( Q(instance_of=Model2C) )
>>> Model2A.objects.filter(q)
[ <Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>,
<Model2D: id 4, field1 (CharField), field2 (CharField), field3 (CharField), field4 (CharField)> ]
### test inheritance pointers & _base_managers
Expand Down
4 changes: 2 additions & 2 deletions polymorphic/test_tools.py → polymorphic/tools_for_tests.py
Expand Up @@ -82,7 +82,7 @@ def create_uuid(self):
else:
raise UUIDVersionError("UUID version %s is not valid." % self.version)

def db_type(self):
def db_type(self, connection):
from django.conf import settings
return UUIDField._CREATE_COLUMN_TYPES.get(settings.DATABASE_ENGINE, "char(%s)" % self.max_length)

Expand Down Expand Up @@ -122,7 +122,7 @@ def pre_save(self, model_instance, add):
setattr(model_instance, self.attname, value)
return value

def get_db_prep_value(self, value):
def get_db_prep_value(self, value, connection, prepared):
"""Casts uuid.UUID values into the format expected by the back end for use in queries"""
if isinstance(value, uuid.UUID):
return smart_unicode(value)
Expand Down

0 comments on commit 4a4cfd8

Please sign in to comment.