Restructured django_polymorphic into a regular add-on application.

This is needed for the management commands, and also seems
to be a generally good idea for future viablity as well.
Also misc documentation updates.
fix_request_path_info
Bert Constantin 2010-01-29 00:41:54 +01:00
parent dd84e911d0
commit 8bdda93e76
22 changed files with 306 additions and 202 deletions

View File

@ -9,6 +9,8 @@ Requirements
Django 1.1 (or later) and Python 2.5 (or later). This code has been tested
on Django 1.1.1 / 1.2 alpha and Python 2.5.4 / 2.6.4 on Linux.
Django's ContentType framework is used (part of Django).
Testing
-------
@ -18,20 +20,28 @@ that may be used for tests or experiments.
To run the included test suite, execute::
./manage test poly
./manage test polymorphic
'management/commands/polycmd.py' can be used for experiments
- modify this file to your liking, then run::
The management command ``pcmd.py`` in the app ``pexp`` (Polymorphic EXPerimenting)
can be used for experiments - modify this file (pexp/management/commands/pcmd.py)
to your liking, then run::
./manage syncdb # db is created in /var/tmp/... (settings.py)
./manage polycmd
./manage pcmd
Using polymorphic models in your own projects
---------------------------------------------
Copy polymorphic.py (from the 'poly' dir) into a directory from where
you can import it, like your app directory (where your models.py and
views.py files live).
The best way for now is probably to just copy the ``polymorphic`` directory
into your project dir. If you want to use the management command
``polymorphic_dumpdata``, then you also need to add ``polymorphic``
to your INSTALLED_APPS setting. The ContentType framework
(``django.contrib.contenttypes``) needs to be listed in INSTALLED_APPS
as well (usually it already is).
It's also still possible to use ``polymorphic.py`` only, as a single file
add-on module, copied to somewhere where it can be imported (like your
own app dir).
Defining Polymorphic Models
@ -41,7 +51,7 @@ To make models polymorphic, use ``PolymorphicModel`` instead of Django's
``models.Model`` as the superclass of your base model. All models
inheriting from your base class will be polymorphic as well::
from polymorphic import PolymorphicModel
from polymorphic.models import PolymorphicModel
class ModelA(PolymorphicModel):
field1 = models.CharField(max_length=10)
@ -177,6 +187,15 @@ Non-Polymorphic Queries
Django manager. Of course, arbitrary custom managers may be
added to the models as well.
manage.py dumpdata
------------------
Django's standard ``dumpdata`` requires non-polymorphic
behaviour from the querysets it uses and produces incomplete
results with polymorphic models. Django_polymorphic includes
a slightly modified version, named ``polymorphic_dumpdata``.
Just use this command instead of Django's (see "installation/testing").
Custom Managers, Querysets & Inheritance
========================================
@ -205,23 +224,21 @@ the plain ``PolymorphicManager`` here.
Manager Inheritance / Propagation
---------------------------------
Polymorphic models unconditionally inherit all managers from their
base models (as long as these are polymorphic).
Polymorphic models unconditionally propagate (or inherit) all managers from
their base models, as long as these are polymorphic. This means that all
managers inherited from polymorphic base models work just the same as if
they were defined in the new model.
An example (inheriting from MyModel above)::
class MyModel2(MyModel):
pass
# Managers inherited from MyModel, delivering MyModel2 (and subclass) objects
# Managers inherited from MyModel:
# the regular 'objects' manager and the custom 'ordered_objects' manager
>>> MyModel2.objects.all()
>>> MyModel2.ordered_objects.all()
Perhaps a more correct way to describe this: With polymorphic models the
managers are always fully propagated from all polymorphic base models
(as strictly speaking all managers are always inherited with Django models).
Using a Custom Queryset Class
-----------------------------
@ -377,6 +394,10 @@ Restrictions & Caveats
ContentType table needs to be corrected too, if the db content
should stay usable after the rename.
+ The stability of the ``ContentType`` ids when combined with Django's
serialisation / fixtures has not yet been sufficiently
investigated (please see issue 4 on github).
+ For all objects that are not instances of the base class type, but
instances of a subclass, the base class fields are currently
transferred twice from the database (an artefact of the current
@ -393,13 +414,13 @@ Restrictions & Caveats
In General
----------
It is important to consider that this code is still very new and experimental.
It's important to consider that this code is still very new and experimental.
It has, however, been integrated into one larger system where all seems to work flawlessly
so far. A small number of people tested this code for their purposes and reported that it
works well for them.
Right now it's suitable only for the more enterprising early adopters.
Right now this module is suitable only for the more enterprising early adopters.
It does seem to work well for a number of people (including me), but
it's still very early and API changes, code reorganisations or further
schema changes are still a possibility.
Links

View File

@ -8,15 +8,15 @@
Usage, Examples, Installation & Documentation, Links
----------------------------------------------------
* Documentation_ and Overview_
* `Discussion, Questions, Suggestions`_
* GitHub_ - Bitbucket_ - `Download as TGZ`_ or ZIP_
* Please see the `Documentation and Examples`_ (or the short `Overview`_)
* If you have comments or suggestions: `Discussion, Comments, Suggestions`_
* The code can be found on GitHub_ and Bitbucket_, or downloaded as TGZ_ or ZIP_
.. _Documentation: http://bserve.webhop.org/wiki/django_polymorphic/doc
.. _Documentation and Examples: http://bserve.webhop.org/wiki/django_polymorphic/doc
.. _Discussion, Questions, Suggestions: http://django-polymorphic.blogspot.com/2010/01/messages.html
.. _GitHub: http://github.com/bconstantin/django_polymorphic
.. _Bitbucket: http://bitbucket.org/bconstantin/django_polymorphic
.. _Download as TGZ: http://github.com/bconstantin/django_polymorphic/tarball/master
.. _TGZ: http://github.com/bconstantin/django_polymorphic/tarball/master
.. _ZIP: http://github.com/bconstantin/django_polymorphic/zipball/master
.. _Overview: http://bserve.webhop.org/wiki/django_polymorphic
@ -24,32 +24,60 @@ Usage, Examples, Installation & Documentation, Links
What is django_polymorphic good for?
------------------------------------
If ``ArtProject`` and ``ResearchProject`` inherit from the model ``Project``:
It causes objects being retrieved from the database to always be returned back
with the same type/class and fields they were created and saved with.
>>> Project.objects.all()
.
[ <Project: id 1, topic: "John's Gathering">,
Example:
If ``ArtProject`` and ``ResearchProject`` inherit from the model ``Project``,
and we have saved one of each into the database::
>>> Project.objects.all()
.
[ <Project: id 1, topic: "John's Gathering">,
<ArtProject: id 2, topic: "Sculpting with Tim", artist: "T. Turner">,
<ResearchProject: id 3, topic: "Swallow Aerodynamics", supervisor: "Dr. Winter"> ]
In general, objects retrieved from the database are always returned back
with the same type/class and fields they were created and saved with.
It doesn't matter how these objects are retrieved: be it through the
model's own managers/querysets, ForeignKeys, ManyToManyFields
or OneToOneFields.
``django_polymorphic`` does this only for models that explicitly request this behaviour.
The resulting querysets are polymorphic, i.e they may deliver
objects of several different types in a single query result.
``django_polymorphic`` consists of just one add-on module, ``polymorphic.py``,
that adds this functionality to Django's model inheritance system
(for models that request this behaviour).
Status
------
This module is still very experimental. Please see the docs for current restrictions,
caveats, and performance implications.
It's important to consider that this code is still very new and
experimental. Please see the docs for current restrictions, caveats,
and performance implications.
Right now it's suitable only for the more enterprising early adopters.
It does seem to work well for a number of people (including me), but
it's still very early and API changes, code reorganisations or further
schema changes are still a possibility.
News
----
**2010-1-29:**
Restructured django_polymorphic into a regular Django add-on
application. This is needed for the management commands, and
also seems to be a generally good idea for future enhancements
as well (and it makes sure the tests are always included).
The ``poly`` app - until now being used for test purposes only
- has been renamed to ``polymorphic``. See DOCS.rst
("installation/testing") for more info.
**2010-1-26:**
IMPORTANT - database schema change (more info in change log).
I hope I got this change in early enough before anyone started to use
polymorphic.py in earnest. Sorry for any inconvenience.
This should be the final DB schema now.

5
dbreset 100755
View File

@ -0,0 +1,5 @@
#!/bin/bash
rm /var/tmp/django-polymorphic-test-db.sqlite3
./manage.py syncdb

View File

@ -5,10 +5,11 @@ This module is a scratchpad for general development, testing & debugging
from django.core.management.base import NoArgsCommand
from django.db.models import connection
from poly.models import *
from pprint import pprint
import settings
from pexp.models import *
def reset_queries():
connection.queries=[]
@ -22,19 +23,19 @@ class Command(NoArgsCommand):
print 'polycmd - sqlite test db is stored in:',settings.DATABASE_NAME
print
Project.objects.all().delete()
o=Project.objects.create(topic="John's gathering")
o=ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
o=ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
print Project.objects.all()
print
ModelA.objects.all().delete()
o=ModelA.objects.create(field1='A1')
o=ModelB.objects.create(field1='B1', field2='B2')
o=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
print ModelA.objects.all()
print
Project.objects.all().delete()
o=Project.objects.create(topic="John's gathering")
o=ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
o=ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
print Project.objects.all()
print

18
pexp/models.py 100644
View File

@ -0,0 +1,18 @@
from django.db import models
from polymorphic.models import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet, ShowFields, ShowFieldsAndTypes
class Project(ShowFields, 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)
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)

23
pexp/tests.py 100644
View File

@ -0,0 +1,23 @@
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}

1
pexp/views.py 100644
View File

@ -0,0 +1 @@
# Create your views here.

View File

@ -1,11 +0,0 @@
import django
if django.VERSION[:2]==(1,1):
from polymorphic_dumpdata_11 import Command
elif django.VERSION[:2]==(1,2):
from polymorphic_dumpdata_12 import Command
else:
assert False, 'Django version not supported'

View File

@ -1,90 +0,0 @@
from django.db import models
from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet, ShowFields, ShowFieldsAndTypes
class PlainA(models.Model):
field1 = models.CharField(max_length=10)
class PlainB(PlainA):
field2 = models.CharField(max_length=10)
class PlainC(PlainB):
field3 = models.CharField(max_length=10)
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)
class Base(PolymorphicModel):
field_b = models.CharField(max_length=10)
class ModelX(Base):
field_x = models.CharField(max_length=10)
class ModelY(Base):
field_y = models.CharField(max_length=10)
class Enhance_Plain(models.Model):
field_p = models.CharField(max_length=10)
class Enhance_Base(ShowFieldsAndTypes, PolymorphicModel):
field_b = models.CharField(max_length=10)
class Enhance_Inherit(Enhance_Base, Enhance_Plain):
field_i = models.CharField(max_length=10)
class DiamondBase(models.Model):
field_b = models.CharField(max_length=10)
class DiamondX(DiamondBase):
field_x = models.CharField(max_length=10)
class DiamondY(DiamondBase):
field_y = models.CharField(max_length=10)
class DiamondXY(DiamondX, DiamondY):
pass
class RelationBase(ShowFieldsAndTypes, PolymorphicModel):
field_base = models.CharField(max_length=10)
fk = models.ForeignKey('self', null=True)
m2m = models.ManyToManyField('self')
class RelationA(RelationBase):
field_a = models.CharField(max_length=10)
class RelationB(RelationBase):
field_b = models.CharField(max_length=10)
class RelationBC(RelationB):
field_c = models.CharField(max_length=10)
class RelatingModel(models.Model):
many2many = models.ManyToManyField(ModelA)
class MyManager(PolymorphicManager):
def get_query_set(self):
return super(MyManager, self).get_query_set().order_by('-field1')
class ModelWithMyManager(ShowFieldsAndTypes, ModelA):
objects = MyManager()
field4 = models.CharField(max_length=10)
class MROBase1(PolymorphicModel):
objects = MyManager()
field1 = models.CharField(max_length=10) # needed as MyManager uses it
class MROBase2(MROBase1):
pass # Django vanilla inheritance does not inherit MyManager as _default_manager here
class MROBase3(models.Model):
objects = PolymorphicManager()
class MRODerived(MROBase2, MROBase3):
pass
class MgrInheritA(models.Model):
mgrA = models.Manager()
mgrA2 = models.Manager()
field1 = models.CharField(max_length=10)
class MgrInheritB(MgrInheritA):
mgrB = models.Manager()
field2 = models.CharField(max_length=10)
class MgrInheritC(ShowFieldsAndTypes, MgrInheritB):
pass
class Project(ShowFields,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)

View File

View File

@ -0,0 +1,19 @@
"""
polymorphic_dumpdata is just a slightly modified version
of Django's dumpdata. In the long term, patching Django's
dumpdata definitely is a better solution.
Use the Django 1.1 or 1.2 variant of dumpdata, depending of the
Django version used.
"""
import django
if django.VERSION[:2]==(1,1):
from polymorphic_dumpdata_11 import Command
elif django.VERSION[:2]==(1,2):
from polymorphic_dumpdata_12 import Command
else:
assert False, 'Django version not supported'

View File

@ -75,6 +75,8 @@ class Command(BaseCommand):
for model in model_list:
if not model._meta.proxy:
#### patch for django_polymorphic ######################################################
# modified for django_polymorphic compatibility:
# do not use polymorphic queryset for serialisation
# (as the dumpdata/serializer implementation depends

View File

@ -80,6 +80,8 @@ class Command(BaseCommand):
objects = []
for model in sort_dependencies(app_list.items()):
if not model._meta.proxy:
#### patch for django_polymorphic ######################################################
# modified for django_polymorphic compatibility:
# do not use polymorphic queryset for serialisation
# (as the dumpdata/serializer implementation depends

View File

@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet, ShowFields, ShowFieldsAndTypes

View File

@ -321,7 +321,7 @@ def _translate_polymorphic_field_path(queryset_model, field_path):
submodels = {}
add_all_sub_models(queryset_model, submodels)
model = submodels.get(classname, None)
assert model, 'PolymorphicModel: model %s not found (not a subclass of %s)!' % (model.__name__, queryset_model.__name__)
assert model, 'PolymorphicModel: model %s not found (not a subclass of %s)!' % (classname, queryset_model.__name__)
# create new field path for expressions, e.g. for baseclass=ModelA, myclass=ModelC
# 'modelb__modelc" is returned

View File

@ -1,6 +1,104 @@
# -*- coding: utf-8 -*-
#disabletests = 1
"""
import settings
from django.test import TestCase
from django.db.models.query import QuerySet
from django.db.models import Q
from django.db import models
from models import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet, ShowFields, ShowFieldsAndTypes
class PlainA(models.Model):
field1 = models.CharField(max_length=10)
class PlainB(PlainA):
field2 = models.CharField(max_length=10)
class PlainC(PlainB):
field3 = models.CharField(max_length=10)
class Model2A(PolymorphicModel):
field1 = models.CharField(max_length=10)
class Model2B(Model2A):
field2 = models.CharField(max_length=10)
class Model2C(Model2B):
field3 = models.CharField(max_length=10)
class Base(PolymorphicModel):
field_b = models.CharField(max_length=10)
class ModelX(Base):
field_x = models.CharField(max_length=10)
class ModelY(Base):
field_y = models.CharField(max_length=10)
class Enhance_Plain(models.Model):
field_p = models.CharField(max_length=10)
class Enhance_Base(ShowFieldsAndTypes, PolymorphicModel):
field_b = models.CharField(max_length=10)
class Enhance_Inherit(Enhance_Base, Enhance_Plain):
field_i = models.CharField(max_length=10)
class DiamondBase(models.Model):
field_b = models.CharField(max_length=10)
class DiamondX(DiamondBase):
field_x = models.CharField(max_length=10)
class DiamondY(DiamondBase):
field_y = models.CharField(max_length=10)
class DiamondXY(DiamondX, DiamondY):
pass
class RelationBase(ShowFieldsAndTypes, PolymorphicModel):
field_base = models.CharField(max_length=10)
fk = models.ForeignKey('self', null=True)
m2m = models.ManyToManyField('self')
class RelationA(RelationBase):
field_a = models.CharField(max_length=10)
class RelationB(RelationBase):
field_b = models.CharField(max_length=10)
class RelationBC(RelationB):
field_c = models.CharField(max_length=10)
class RelatingModel(models.Model):
many2many = models.ManyToManyField(Model2A)
class MyManager(PolymorphicManager):
def get_query_set(self):
return super(MyManager, self).get_query_set().order_by('-field1')
class ModelWithMyManager(ShowFieldsAndTypes, Model2A):
objects = MyManager()
field4 = models.CharField(max_length=10)
class MROBase1(PolymorphicModel):
objects = MyManager()
field1 = models.CharField(max_length=10) # needed as MyManager uses it
class MROBase2(MROBase1):
pass # Django vanilla inheritance does not inherit MyManager as _default_manager here
class MROBase3(models.Model):
objects = PolymorphicManager()
class MRODerived(MROBase2, MROBase3):
pass
class MgrInheritA(models.Model):
mgrA = models.Manager()
mgrA2 = models.Manager()
field1 = models.CharField(max_length=10)
class MgrInheritB(MgrInheritA):
mgrB = models.Manager()
field2 = models.CharField(max_length=10)
class MgrInheritC(ShowFieldsAndTypes, MgrInheritB):
pass
class testclass(TestCase):
def test_diamond_inheritance(self):
# Django diamond problem
o = DiamondXY.objects.create(field_b='b', field_x='x', field_y='y')
print 'DiamondXY fields 1: field_b "%s", field_x "%s", field_y "%s"' % (o.field_b, o.field_x, o.field_y)
o = DiamondXY.objects.get()
print 'DiamondXY fields 2: field_b "%s", field_x "%s", field_y "%s"' % (o.field_b, o.field_x, o.field_y)
if o.field_b != 'b': print '# Django model inheritance diamond problem detected'
__test__ = {"doctest": """
#######################################################
### Tests
@ -8,45 +106,45 @@
### simple inheritance
>>> o=ModelA.objects.create(field1='A1')
>>> o=ModelB.objects.create(field1='B1', field2='B2')
>>> o=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
>>> o=Model2A.objects.create(field1='A1')
>>> o=Model2B.objects.create(field1='B1', field2='B2')
>>> o=Model2C.objects.create(field1='C1', field2='C2', field3='C3')
>>> ModelA.objects.all()
[ <ModelA: id 1, field1 (CharField)>,
<ModelB: id 2, field1 (CharField), field2 (CharField)>,
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
>>> Model2A.objects.all()
[ <Model2A: id 1, field1 (CharField)>,
<Model2B: id 2, field1 (CharField), field2 (CharField)>,
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
# manual get_real_instance()
>>> o=ModelA.base_objects.get(field1='C1')
>>> o=Model2A.base_objects.get(field1='C1')
>>> o.get_real_instance()
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>
### class filtering, instance_of, not_instance_of
>>> ModelA.objects.instance_of(ModelB)
[ <ModelB: id 2, field1 (CharField), field2 (CharField)>,
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
>>> Model2A.objects.instance_of(Model2B)
[ <Model2B: id 2, field1 (CharField), field2 (CharField)>,
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
>>> ModelA.objects.not_instance_of(ModelB)
[ <ModelA: id 1, field1 (CharField)> ]
>>> Model2A.objects.not_instance_of(Model2B)
[ <Model2A: id 1, field1 (CharField)> ]
### polymorphic filtering
>>> ModelA.objects.filter( Q( ModelB___field2 = 'B2' ) | Q( ModelC___field3 = 'C3' ) )
[ <ModelB: id 2, field1 (CharField), field2 (CharField)>,
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
>>> Model2A.objects.filter( Q( Model2B___field2 = 'B2' ) | Q( Model2C___field3 = 'C3' ) )
[ <Model2B: id 2, field1 (CharField), field2 (CharField)>,
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
### get & delete
>>> oa=ModelA.objects.get(id=2)
>>> oa=Model2A.objects.get(id=2)
>>> oa
<ModelB: id 2, field1 (CharField), field2 (CharField)>
<Model2B: id 2, field1 (CharField), field2 (CharField)>
>>> oa.delete()
>>> ModelA.objects.all()
[ <ModelA: id 1, field1 (CharField)>,
<ModelC: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
>>> Model2A.objects.all()
[ <Model2A: id 1, field1 (CharField)>,
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
### queryset combining
@ -107,22 +205,22 @@
<ModelWithMyManager: id 4, field1 (CharField): "D1a", field4 (CharField): "D4a"> ]
>>> type(ModelWithMyManager.objects)
<class 'poly.models.MyManager'>
<class 'polymorphic.tests.MyManager'>
>>> type(ModelWithMyManager._default_manager)
<class 'poly.models.MyManager'>
<class 'polymorphic.tests.MyManager'>
### Manager Inheritance
>>> type(MRODerived.objects) # MRO
<class 'poly.models.MyManager'>
<class 'polymorphic.tests.MyManager'>
# check for correct default manager
>>> type(MROBase1._default_manager)
<class 'poly.models.MyManager'>
<class 'polymorphic.tests.MyManager'>
# Django vanilla inheritance does not inherit MyManager as _default_manager here
>>> type(MROBase2._default_manager)
<class 'poly.models.MyManager'>
<class 'polymorphic.tests.MyManager'>
### Django model inheritance diamond problem, fails for Django 1.1
@ -132,22 +230,5 @@
>>> settings.DEBUG=False
"""
import settings
from django.test import TestCase
from django.db.models.query import QuerySet
from django.db.models import Q
from models import *
class testclass(TestCase):
def test_diamond_inheritance(self):
# Django diamond problem
o = DiamondXY.objects.create(field_b='b', field_x='x', field_y='y')
print 'DiamondXY fields 1: field_b "%s", field_x "%s", field_y "%s"' % (o.field_b, o.field_x, o.field_y)
o = DiamondXY.objects.get()
print 'DiamondXY fields 2: field_b "%s", field_x "%s", field_y "%s"' % (o.field_b, o.field_x, o.field_y)
if o.field_b != 'b': print '# Django model inheritance diamond problem detected'
"""}

View File

@ -77,5 +77,6 @@ INSTALLED_APPS = (
'django.contrib.contenttypes',
#'django.contrib.sessions',
#'django.contrib.sites',
'poly', # this Django app is for testing and experimentation; not needed otherwise
'polymorphic', # only needed if you want to use polymorphic_dumpdata
'pexp', # this Django app is for testing and experimentation; not needed otherwise
)