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
parent
dd84e911d0
commit
8bdda93e76
63
DOCS.rst
63
DOCS.rst
|
|
@ -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
|
||||
|
|
|
|||
62
README.rst
62
README.rst
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
rm /var/tmp/django-polymorphic-test-db.sqlite3
|
||||
./manage.py syncdb
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
"""}
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
# Create your views here.
|
||||
|
|
@ -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'
|
||||
|
|
@ -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)
|
||||
|
||||
|
|
@ -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'
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet, ShowFields, ShowFieldsAndTypes
|
||||
|
|
@ -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
|
||||
|
|
@ -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'
|
||||
"""}
|
||||
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue