- renamed ShowField* to ShowFieldType, ShowFieldContent, ShowFieldTypeAndContent, in order to reflect better what they do.
- by default, django_polymorphic's pretty printing of querysets/objects (via ShowField*) is not used anymore - ShowField mixins now also show the annotations (after the regular fields, prepended by "Ann:") - cleaned up implementation.fix_request_path_info
parent
50b54f5aca
commit
01bdb2f9b0
|
|
@ -15,11 +15,14 @@ pushhg
|
||||||
pushreg
|
pushreg
|
||||||
pbackup
|
pbackup
|
||||||
mcmd.py
|
mcmd.py
|
||||||
|
dbconfig_local.py
|
||||||
|
|
||||||
pip-log.txt
|
pip-log.txt
|
||||||
build
|
build
|
||||||
ppreadme.py
|
ppreadme.py
|
||||||
ppdocs.py
|
ppdocs.py
|
||||||
|
common.css
|
||||||
|
screen.css
|
||||||
README.html
|
README.html
|
||||||
DOCS.html
|
DOCS.html
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,14 @@ class Command(NoArgsCommand):
|
||||||
print 'polycmd - sqlite test db is stored in:',settings.DATABASE_NAME
|
print 'polycmd - sqlite test db is stored in:',settings.DATABASE_NAME
|
||||||
print
|
print
|
||||||
|
|
||||||
|
"""
|
||||||
ModelA.objects.all().delete()
|
ModelA.objects.all().delete()
|
||||||
o=ModelA.objects.create(field1='A1')
|
o=ModelA.objects.create(field1='A1')
|
||||||
o=ModelB.objects.create(field1='B1', field2='B2')
|
o=ModelB.objects.create(field1='B1', field2='B2')
|
||||||
o=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
o=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
|
||||||
print ModelA.objects.all()
|
print ModelA.objects.all()
|
||||||
print
|
print
|
||||||
|
"""
|
||||||
|
|
||||||
Project.objects.all().delete()
|
Project.objects.all().delete()
|
||||||
o=Project.objects.create(topic="John's gathering")
|
o=Project.objects.create(topic="John's gathering")
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,24 @@
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet, ShowFields, ShowFieldsAndTypes
|
from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet
|
||||||
|
from polymorphic.showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
||||||
|
|
||||||
|
|
||||||
class Project(ShowFields, PolymorphicModel):
|
class Project(ShowFieldContent, PolymorphicModel):
|
||||||
topic = models.CharField(max_length=30)
|
topic = models.CharField(max_length=30)
|
||||||
class ArtProject(Project):
|
class ArtProject(Project):
|
||||||
artist = models.CharField(max_length=30)
|
artist = models.CharField(max_length=30)
|
||||||
class ResearchProject(Project):
|
class ResearchProject(Project):
|
||||||
supervisor = models.CharField(max_length=30)
|
supervisor = models.CharField(max_length=30)
|
||||||
|
|
||||||
class ModelA(PolymorphicModel):
|
class ModelA(ShowFieldType, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
class ModelB(ModelA):
|
class ModelB(ModelA):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
class ModelC(ModelB):
|
class ModelC(ModelB):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
class SModelA(ShowFieldsAndTypes, PolymorphicModel):
|
|
||||||
field1 = models.CharField(max_length=10)
|
|
||||||
class SModelB(SModelA):
|
|
||||||
field2 = models.CharField(max_length=10)
|
|
||||||
class SModelC(SModelB):
|
|
||||||
field3 = models.CharField(max_length=10)
|
|
||||||
|
|
||||||
# for Django 1.2+, test models with same names in different apps
|
# for Django 1.2+, test models with same names in different apps
|
||||||
# (the other models with identical names are in polymorphic/tests.py)
|
# (the other models with identical names are in polymorphic/tests.py)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ Please see LICENSE and AUTHORS for more information.
|
||||||
from polymorphic_model import PolymorphicModel
|
from polymorphic_model import PolymorphicModel
|
||||||
from manager import PolymorphicManager
|
from manager import PolymorphicManager
|
||||||
from query import PolymorphicQuerySet
|
from query import PolymorphicQuerySet
|
||||||
from showfields import ShowFields, ShowFieldsAndTypes
|
from showfields import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent
|
||||||
|
#from showfields import ShowFieldTypes, ShowFields, ShowFieldsAndTypes # import old names for compatibility
|
||||||
|
|
||||||
|
|
||||||
VERSION = (0, 5, 0, 'beta')
|
VERSION = (0, 5, 0, 'beta')
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,13 @@ from django import VERSION as django_VERSION
|
||||||
from base import PolymorphicModelBase
|
from base import PolymorphicModelBase
|
||||||
from manager import PolymorphicManager
|
from manager import PolymorphicManager
|
||||||
from query import PolymorphicQuerySet
|
from query import PolymorphicQuerySet
|
||||||
from showfields import ShowFieldTypes
|
from showfields import ShowFieldType
|
||||||
|
|
||||||
|
|
||||||
###################################################################################
|
###################################################################################
|
||||||
### PolymorphicModel
|
### PolymorphicModel
|
||||||
|
|
||||||
class PolymorphicModel(ShowFieldTypes, models.Model):
|
class PolymorphicModel(models.Model):
|
||||||
"""
|
"""
|
||||||
Abstract base class that provides polymorphic behaviour
|
Abstract base class that provides polymorphic behaviour
|
||||||
for any model directly or indirectly derived from it.
|
for any model directly or indirectly derived from it.
|
||||||
|
|
@ -53,7 +53,11 @@ class PolymorphicModel(ShowFieldTypes, models.Model):
|
||||||
"""
|
"""
|
||||||
__metaclass__ = PolymorphicModelBase
|
__metaclass__ = PolymorphicModelBase
|
||||||
|
|
||||||
polymorphic_model_marker = True # for PolymorphicModelBase
|
# for PolymorphicModelBase, so it can tell which models are polymorphic and which are not (duck typing)
|
||||||
|
polymorphic_model_marker = True
|
||||||
|
|
||||||
|
# for PolymorphicQuery, True => an overloaded __repr__ with nicer multi-line output is used by PolymorphicQuery
|
||||||
|
polymorphic_query_multiline_output = False
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
@ -130,10 +134,12 @@ class PolymorphicModel(ShowFieldTypes, models.Model):
|
||||||
name = model.__name__.lower()
|
name = model.__name__.lower()
|
||||||
if as_ptr: name+='_ptr'
|
if as_ptr: name+='_ptr'
|
||||||
result[name] = model
|
result[name] = model
|
||||||
|
|
||||||
def add_all_base_models(model, result):
|
def add_all_base_models(model, result):
|
||||||
add_if_regular_sub_or_super_class(model, True, result)
|
add_if_regular_sub_or_super_class(model, True, result)
|
||||||
for b in model.__bases__:
|
for b in model.__bases__:
|
||||||
add_all_base_models(b, result)
|
add_all_base_models(b, result)
|
||||||
|
|
||||||
def add_sub_models(model, result):
|
def add_sub_models(model, result):
|
||||||
for b in model.__subclasses__():
|
for b in model.__subclasses__():
|
||||||
add_if_regular_sub_or_super_class(b, False, result)
|
add_if_regular_sub_or_super_class(b, False, result)
|
||||||
|
|
@ -150,6 +156,6 @@ class PolymorphicModel(ShowFieldTypes, models.Model):
|
||||||
attr = model.base_objects.get(id=id)
|
attr = model.base_objects.get(id=id)
|
||||||
#print '---',self.__class__.__name__,name
|
#print '---',self.__class__.__name__,name
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
return super(PolymorphicModel, self).__getattribute__(name)
|
return super(PolymorphicModel, self).__getattribute__(name)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,7 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
for modelclass, idlist in idlist_per_model.items():
|
for modelclass, idlist in idlist_per_model.items():
|
||||||
qs = modelclass.base_objects.filter(id__in=idlist)
|
qs = modelclass.base_objects.filter(id__in=idlist)
|
||||||
qs.dup_select_related(self) # copy select related configuration to new qs
|
qs.dup_select_related(self) # copy select related configuration to new qs
|
||||||
|
|
||||||
for o in qs:
|
for o in qs:
|
||||||
if self.query.aggregates:
|
if self.query.aggregates:
|
||||||
for anno in self.query.aggregates.keys():
|
for anno in self.query.aggregates.keys():
|
||||||
|
|
@ -153,6 +154,13 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
|
|
||||||
# re-create correct order and return result list
|
# re-create correct order and return result list
|
||||||
resultlist = [ results[ordered_id] for ordered_id in ordered_id_list if ordered_id in results ]
|
resultlist = [ results[ordered_id] for ordered_id in ordered_id_list if ordered_id in results ]
|
||||||
|
|
||||||
|
# set polymorphic_annotate_names in all objects (currently just used for debugging/printing)
|
||||||
|
if self.query.aggregates:
|
||||||
|
annotate_names=self.query.aggregates.keys() # get annotate fields list
|
||||||
|
for o in resultlist:
|
||||||
|
o.polymorphic_annotate_names=annotate_names
|
||||||
|
|
||||||
return resultlist
|
return resultlist
|
||||||
|
|
||||||
def iterator(self):
|
def iterator(self):
|
||||||
|
|
@ -182,7 +190,9 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
reached_end = False
|
reached_end = False
|
||||||
|
|
||||||
for i in range(Polymorphic_QuerySet_objects_per_request):
|
for i in range(Polymorphic_QuerySet_objects_per_request):
|
||||||
try: base_result_objects.append(base_iter.next())
|
try:
|
||||||
|
o=base_iter.next()
|
||||||
|
base_result_objects.append(o)
|
||||||
except StopIteration:
|
except StopIteration:
|
||||||
reached_end = True
|
reached_end = True
|
||||||
break
|
break
|
||||||
|
|
@ -194,8 +204,10 @@ class PolymorphicQuerySet(QuerySet):
|
||||||
|
|
||||||
if reached_end: raise StopIteration
|
if reached_end: raise StopIteration
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self, *args, **kwargs):
|
||||||
|
if self.model.polymorphic_query_multiline_output:
|
||||||
result = [ repr(o) for o in self.all() ]
|
result = [ repr(o) for o in self.all() ]
|
||||||
return '[ ' + ',\n '.join(result) + ' ]'
|
return '[ ' + ',\n '.join(result) + ' ]'
|
||||||
|
else:
|
||||||
|
return super(PolymorphicQuerySet,self).__repr__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,49 +2,67 @@
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
|
||||||
def _represent_foreign_key(o):
|
|
||||||
if o is None:
|
|
||||||
out = '"None"'
|
|
||||||
else:
|
|
||||||
out = '"' + o.__class__.__name__ + '"'
|
|
||||||
return out
|
|
||||||
|
|
||||||
class ShowFieldsAndTypes(object):
|
class ShowFieldBase(object):
|
||||||
""" model mixin, like ShowFields, but also show field types """
|
""" base class for the ShowField... model mixins, does the work """
|
||||||
def __repr__(self):
|
polymorphic_query_multiline_output = True # cause nicer multiline PolymorphicQuery output
|
||||||
out = 'id ' + str(self.pk)
|
|
||||||
for f in self._meta.fields:
|
polymorphic_showfield_type = False
|
||||||
if f.name in [ 'id' ] + self.polymorphic_internal_model_fields or 'ptr' in f.name: continue
|
polymorphic_showfield_content = False
|
||||||
out += ', ' + f.name + ' (' + type(f).__name__ + ')'
|
|
||||||
if isinstance(f, (models.ForeignKey)):
|
|
||||||
o = getattr(self, f.name)
|
|
||||||
out += ': ' + _represent_foreign_key(o)
|
|
||||||
else:
|
|
||||||
out += ': "' + getattr(self, f.name) + '"'
|
|
||||||
return '<' + self.__class__.__name__ + ': ' + out + '>'
|
|
||||||
|
|
||||||
class ShowFields(object):
|
|
||||||
""" model mixin that shows the object's class, it's fields and field contents """
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
out = 'id ' + str(self.pk) + ', '
|
return self.__unicode__()
|
||||||
for f in self._meta.fields:
|
|
||||||
|
def __unicode__(self):
|
||||||
|
out = u'<'+self.__class__.__name__+': id %s' % unicode(self.pk)
|
||||||
|
for f in self._meta.fields + self._meta.many_to_many:
|
||||||
|
|
||||||
if f.name in [ 'id' ] + self.polymorphic_internal_model_fields or 'ptr' in f.name: continue
|
if f.name in [ 'id' ] + self.polymorphic_internal_model_fields or 'ptr' in f.name: continue
|
||||||
out += ', ' + f.name
|
out += ', ' + f.name
|
||||||
if isinstance(f, (models.ForeignKey)):
|
|
||||||
|
if self.polymorphic_showfield_type:
|
||||||
|
out += ' (' + type(f).__name__ + ')'
|
||||||
|
|
||||||
|
if self.polymorphic_showfield_content:
|
||||||
o = getattr(self, f.name)
|
o = getattr(self, f.name)
|
||||||
out += ': ' + _represent_foreign_key(o)
|
|
||||||
|
if isinstance(f, (models.ForeignKey)):
|
||||||
|
out += ': ' + ( '"None"' if o is None else '"' + o.__class__.__name__ + '"' )
|
||||||
|
|
||||||
|
elif isinstance(f, (models.ManyToManyField)):
|
||||||
|
out += ': %d' % o.count()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
out += ': "' + getattr(self, f.name) + '"'
|
out += ': "' + unicode(o) + '"'
|
||||||
return '<' + (self.__class__.__name__ + ': ') + out + '>'
|
|
||||||
|
|
||||||
class ShowFieldTypes(object):
|
if hasattr(self,'polymorphic_annotate_names'):
|
||||||
""" INTERNAL; don't use this!
|
out += ' - Ann: '
|
||||||
This mixin is already used by default by PolymorphicModel.
|
for an in self.polymorphic_annotate_names:
|
||||||
(model mixin that shows the object's class and it's field types) """
|
if an != self.polymorphic_annotate_names[0]:
|
||||||
def __repr__(self):
|
out += ', '
|
||||||
out = self.__class__.__name__ + ': id ' + str(self.pk)
|
out += an
|
||||||
for f in self._meta.fields:
|
if self.polymorphic_showfield_type:
|
||||||
if f.name in [ 'id' ] + self.polymorphic_internal_model_fields or 'ptr' in f.name: continue
|
out += ' (' + type(getattr(self, an)).__name__ + ')'
|
||||||
out += ', ' + f.name + ' (' + type(f).__name__ + ')'
|
if self.polymorphic_showfield_content:
|
||||||
return '<' + out + '>'
|
out += ': "' + unicode(getattr(self, an)) + '"'
|
||||||
|
|
||||||
|
return out+'>'
|
||||||
|
|
||||||
|
class ShowFieldType(ShowFieldBase):
|
||||||
|
""" model mixin that shows the object's class and it's field types """
|
||||||
|
polymorphic_showfield_type = True
|
||||||
|
|
||||||
|
class ShowFieldContent(ShowFieldBase):
|
||||||
|
""" model mixin that shows the object's class, it's fields and field contents """
|
||||||
|
polymorphic_showfield_content = True
|
||||||
|
|
||||||
|
class ShowFieldTypeAndContent(ShowFieldBase):
|
||||||
|
""" model mixin, like ShowFieldContent, but also show field types """
|
||||||
|
polymorphic_showfield_type = True
|
||||||
|
polymorphic_showfield_content = True
|
||||||
|
|
||||||
|
|
||||||
|
# compatibility with old class names
|
||||||
|
ShowFieldTypes = ShowFieldType
|
||||||
|
ShowFields = ShowFieldContent
|
||||||
|
ShowFieldsAndTypes = ShowFieldTypeAndContent
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,12 @@ import settings
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
from django.db.models import Q
|
from django.db.models import Q,Count
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet, ShowFields, ShowFieldsAndTypes, get_version
|
from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet, ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent, get_version
|
||||||
|
|
||||||
class PlainA(models.Model):
|
class PlainA(models.Model):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
|
|
@ -20,14 +21,24 @@ class PlainB(PlainA):
|
||||||
class PlainC(PlainB):
|
class PlainC(PlainB):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
class Model2A(PolymorphicModel):
|
class Model2A(ShowFieldType, PolymorphicModel):
|
||||||
field1 = models.CharField(max_length=10)
|
field1 = models.CharField(max_length=10)
|
||||||
class Model2B(Model2A):
|
class Model2B(Model2A):
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
class Model2C(Model2B):
|
class Model2C(Model2B):
|
||||||
field3 = models.CharField(max_length=10)
|
field3 = models.CharField(max_length=10)
|
||||||
|
|
||||||
class Base(PolymorphicModel):
|
class ModelShow1(ShowFieldType,PolymorphicModel):
|
||||||
|
field1 = models.CharField(max_length=10)
|
||||||
|
m2m = models.ManyToManyField('self')
|
||||||
|
class ModelShow2(ShowFieldContent, PolymorphicModel):
|
||||||
|
field1 = models.CharField(max_length=10)
|
||||||
|
m2m = models.ManyToManyField('self')
|
||||||
|
class ModelShow3(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
|
field1 = models.CharField(max_length=10)
|
||||||
|
m2m = models.ManyToManyField('self')
|
||||||
|
|
||||||
|
class Base(ShowFieldType, PolymorphicModel):
|
||||||
field_b = models.CharField(max_length=10)
|
field_b = models.CharField(max_length=10)
|
||||||
class ModelX(Base):
|
class ModelX(Base):
|
||||||
field_x = models.CharField(max_length=10)
|
field_x = models.CharField(max_length=10)
|
||||||
|
|
@ -36,7 +47,7 @@ class ModelY(Base):
|
||||||
|
|
||||||
class Enhance_Plain(models.Model):
|
class Enhance_Plain(models.Model):
|
||||||
field_p = models.CharField(max_length=10)
|
field_p = models.CharField(max_length=10)
|
||||||
class Enhance_Base(ShowFieldsAndTypes, PolymorphicModel):
|
class Enhance_Base(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
field_b = models.CharField(max_length=10)
|
field_b = models.CharField(max_length=10)
|
||||||
class Enhance_Inherit(Enhance_Base, Enhance_Plain):
|
class Enhance_Inherit(Enhance_Base, Enhance_Plain):
|
||||||
field_i = models.CharField(max_length=10)
|
field_i = models.CharField(max_length=10)
|
||||||
|
|
@ -51,7 +62,7 @@ class DiamondY(DiamondBase):
|
||||||
class DiamondXY(DiamondX, DiamondY):
|
class DiamondXY(DiamondX, DiamondY):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class RelationBase(ShowFieldsAndTypes, PolymorphicModel):
|
class RelationBase(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
field_base = models.CharField(max_length=10)
|
field_base = models.CharField(max_length=10)
|
||||||
fk = models.ForeignKey('self', null=True)
|
fk = models.ForeignKey('self', null=True)
|
||||||
m2m = models.ManyToManyField('self')
|
m2m = models.ManyToManyField('self')
|
||||||
|
|
@ -68,11 +79,11 @@ class RelatingModel(models.Model):
|
||||||
class MyManager(PolymorphicManager):
|
class MyManager(PolymorphicManager):
|
||||||
def get_query_set(self):
|
def get_query_set(self):
|
||||||
return super(MyManager, self).get_query_set().order_by('-field1')
|
return super(MyManager, self).get_query_set().order_by('-field1')
|
||||||
class ModelWithMyManager(ShowFieldsAndTypes, Model2A):
|
class ModelWithMyManager(ShowFieldTypeAndContent, Model2A):
|
||||||
objects = MyManager()
|
objects = MyManager()
|
||||||
field4 = models.CharField(max_length=10)
|
field4 = models.CharField(max_length=10)
|
||||||
|
|
||||||
class MROBase1(PolymorphicModel):
|
class MROBase1(ShowFieldType, PolymorphicModel):
|
||||||
objects = MyManager()
|
objects = MyManager()
|
||||||
field1 = models.CharField(max_length=10) # needed as MyManager uses it
|
field1 = models.CharField(max_length=10) # needed as MyManager uses it
|
||||||
class MROBase2(MROBase1):
|
class MROBase2(MROBase1):
|
||||||
|
|
@ -89,23 +100,23 @@ class MgrInheritA(models.Model):
|
||||||
class MgrInheritB(MgrInheritA):
|
class MgrInheritB(MgrInheritA):
|
||||||
mgrB = models.Manager()
|
mgrB = models.Manager()
|
||||||
field2 = models.CharField(max_length=10)
|
field2 = models.CharField(max_length=10)
|
||||||
class MgrInheritC(ShowFieldsAndTypes, MgrInheritB):
|
class MgrInheritC(ShowFieldTypeAndContent, MgrInheritB):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class BlogBase(ShowFieldsAndTypes, PolymorphicModel):
|
class BlogBase(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
name = models.CharField(max_length=10)
|
name = models.CharField(max_length=10)
|
||||||
class BlogA(BlogBase):
|
class BlogA(BlogBase):
|
||||||
info = models.CharField(max_length=10)
|
info = models.CharField(max_length=10)
|
||||||
class BlogB(BlogBase):
|
class BlogB(BlogBase):
|
||||||
pass
|
pass
|
||||||
class BlogA_Entry(ShowFieldsAndTypes, PolymorphicModel):
|
class BlogEntry(ShowFieldTypeAndContent, PolymorphicModel):
|
||||||
blog = models.ForeignKey(BlogA)
|
blog = models.ForeignKey(BlogA)
|
||||||
text = models.CharField(max_length=10)
|
text = models.CharField(max_length=10)
|
||||||
|
|
||||||
class ModelFieldNameTest(PolymorphicModel):
|
class ModelFieldNameTest(ShowFieldType, PolymorphicModel):
|
||||||
modelfieldnametest = models.CharField(max_length=10)
|
modelfieldnametest = models.CharField(max_length=10)
|
||||||
|
|
||||||
class InitTestModel(PolymorphicModel):
|
class InitTestModel(ShowFieldType, PolymorphicModel):
|
||||||
bar = models.CharField(max_length=100)
|
bar = models.CharField(max_length=100)
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
kwargs['bar'] = self.x()
|
kwargs['bar'] = self.x()
|
||||||
|
|
@ -115,13 +126,13 @@ class InitTestModelSubclass(InitTestModel):
|
||||||
return 'XYZ'
|
return 'XYZ'
|
||||||
|
|
||||||
# test bad field name
|
# test bad field name
|
||||||
#class TestBadFieldModel(PolymorphicModel):
|
#class TestBadFieldModel(ShowFieldType, PolymorphicModel):
|
||||||
# instance_of = models.CharField(max_length=10)
|
# instance_of = models.CharField(max_length=10)
|
||||||
|
|
||||||
# validation error: "polymorphic.relatednameclash: Accessor for field 'polymorphic_ctype' clashes
|
# validation error: "polymorphic.relatednameclash: Accessor for field 'polymorphic_ctype' clashes
|
||||||
# with related field 'ContentType.relatednameclash_set'." (reported by Andrew Ingram)
|
# with related field 'ContentType.relatednameclash_set'." (reported by Andrew Ingram)
|
||||||
# fixed with related_name
|
# fixed with related_name
|
||||||
class RelatedNameClash(PolymorphicModel):
|
class RelatedNameClash(ShowFieldType, PolymorphicModel):
|
||||||
ctype = models.ForeignKey(ContentType, null=True, editable=False)
|
ctype = models.ForeignKey(ContentType, null=True, editable=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -135,22 +146,29 @@ class testclass(TestCase):
|
||||||
if o.field_b != 'b': print '# Django model inheritance diamond problem detected'
|
if o.field_b != 'b': print '# Django model inheritance diamond problem detected'
|
||||||
|
|
||||||
def test_annotate_aggregate_order(self):
|
def test_annotate_aggregate_order(self):
|
||||||
from django.db.models import Count
|
|
||||||
|
|
||||||
BlogA.objects.all().delete()
|
# create a blog of type BlogA
|
||||||
blog = BlogA.objects.create(name='B1', info='i1')
|
blog = BlogA.objects.create(name='B1', info='i1')
|
||||||
entry1 = blog.bloga_entry_set.create(text='bla')
|
# create two blog entries in BlogA
|
||||||
entry2 = BlogA_Entry.objects.create(blog=blog, text='bla2')
|
entry1 = blog.blogentry_set.create(text='bla')
|
||||||
|
entry2 = BlogEntry.objects.create(blog=blog, text='bla2')
|
||||||
|
|
||||||
# create some BlogB to make the table more diverse
|
# create some blogs of type BlogB to make the BlogBase table data really polymorphic
|
||||||
o = BlogB.objects.create(name='Bb1')
|
o = BlogB.objects.create(name='Bb1')
|
||||||
o = BlogB.objects.create(name='Bb2')
|
o = BlogB.objects.create(name='Bb2')
|
||||||
o = BlogB.objects.create(name='Bb3')
|
o = BlogB.objects.create(name='Bb3')
|
||||||
|
|
||||||
qs = BlogBase.objects.annotate(entrycount=Count('BlogA___bloga_entry'))
|
qs = BlogBase.objects.annotate(entrycount=Count('BlogA___blogentry'))
|
||||||
assert qs[0].entrycount == 2
|
|
||||||
|
|
||||||
x = BlogBase.objects.aggregate(entrycount=Count('BlogA___bloga_entry'))
|
assert len(qs)==4
|
||||||
|
|
||||||
|
for o in qs:
|
||||||
|
if o.name=='B1':
|
||||||
|
assert o.entrycount == 2
|
||||||
|
else:
|
||||||
|
assert o.entrycount == 0
|
||||||
|
|
||||||
|
x = BlogBase.objects.aggregate(entrycount=Count('BlogA___blogentry'))
|
||||||
assert x['entrycount'] == 2
|
assert x['entrycount'] == 2
|
||||||
|
|
||||||
# create some more blogs for next test
|
# create some more blogs for next test
|
||||||
|
|
@ -159,7 +177,8 @@ class testclass(TestCase):
|
||||||
b2 = BlogA.objects.create(name='B4', info='i4')
|
b2 = BlogA.objects.create(name='B4', info='i4')
|
||||||
b2 = BlogA.objects.create(name='B5', info='i5')
|
b2 = BlogA.objects.create(name='B5', info='i5')
|
||||||
|
|
||||||
# test ordering
|
### test ordering for field in all entries
|
||||||
|
|
||||||
expected = '''
|
expected = '''
|
||||||
[ <BlogB: id 4, name (CharField): "Bb3">,
|
[ <BlogB: id 4, name (CharField): "Bb3">,
|
||||||
<BlogB: id 3, name (CharField): "Bb2">,
|
<BlogB: id 3, name (CharField): "Bb2">,
|
||||||
|
|
@ -172,7 +191,10 @@ class testclass(TestCase):
|
||||||
x = '\n' + repr(BlogBase.objects.order_by('-name'))
|
x = '\n' + repr(BlogBase.objects.order_by('-name'))
|
||||||
assert x == expected
|
assert x == expected
|
||||||
|
|
||||||
expected='''
|
### test ordering for field in one subclass only
|
||||||
|
|
||||||
|
# MySQL and SQLite return this order
|
||||||
|
expected1='''
|
||||||
[ <BlogA: id 8, name (CharField): "B5", info (CharField): "i5">,
|
[ <BlogA: id 8, name (CharField): "B5", info (CharField): "i5">,
|
||||||
<BlogA: id 7, name (CharField): "B4", info (CharField): "i4">,
|
<BlogA: id 7, name (CharField): "B4", info (CharField): "i4">,
|
||||||
<BlogA: id 6, name (CharField): "B3", info (CharField): "i3">,
|
<BlogA: id 6, name (CharField): "B3", info (CharField): "i3">,
|
||||||
|
|
@ -181,8 +203,20 @@ class testclass(TestCase):
|
||||||
<BlogB: id 2, name (CharField): "Bb1">,
|
<BlogB: id 2, name (CharField): "Bb1">,
|
||||||
<BlogB: id 3, name (CharField): "Bb2">,
|
<BlogB: id 3, name (CharField): "Bb2">,
|
||||||
<BlogB: id 4, name (CharField): "Bb3"> ]'''
|
<BlogB: id 4, name (CharField): "Bb3"> ]'''
|
||||||
|
|
||||||
|
# PostgreSQL returns this order
|
||||||
|
expected2='''
|
||||||
|
[ <BlogB: id 2, name (CharField): "Bb1">,
|
||||||
|
<BlogB: id 3, name (CharField): "Bb2">,
|
||||||
|
<BlogB: id 4, name (CharField): "Bb3">,
|
||||||
|
<BlogA: id 8, name (CharField): "B5", info (CharField): "i5">,
|
||||||
|
<BlogA: id 7, name (CharField): "B4", info (CharField): "i4">,
|
||||||
|
<BlogA: id 6, name (CharField): "B3", info (CharField): "i3">,
|
||||||
|
<BlogA: id 5, name (CharField): "B2", info (CharField): "i2">,
|
||||||
|
<BlogA: id 1, name (CharField): "B1", info (CharField): "i1"> ]'''
|
||||||
|
|
||||||
x = '\n' + repr(BlogBase.objects.order_by('-BlogA___info'))
|
x = '\n' + repr(BlogBase.objects.order_by('-BlogA___info'))
|
||||||
assert x == expected
|
assert x == expected1 or x == expected2
|
||||||
|
|
||||||
#assert False
|
#assert False
|
||||||
|
|
||||||
|
|
@ -196,6 +230,7 @@ __test__ = {"doctest": """
|
||||||
>>> get_version()
|
>>> get_version()
|
||||||
'0.5 beta'
|
'0.5 beta'
|
||||||
|
|
||||||
|
|
||||||
### simple inheritance
|
### simple inheritance
|
||||||
|
|
||||||
>>> o=Model2A.objects.create(field1='A1')
|
>>> o=Model2A.objects.create(field1='A1')
|
||||||
|
|
@ -212,6 +247,32 @@ __test__ = {"doctest": """
|
||||||
>>> o.get_real_instance()
|
>>> o.get_real_instance()
|
||||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>
|
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)>
|
||||||
|
|
||||||
|
|
||||||
|
### ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent, also with annotate()
|
||||||
|
|
||||||
|
>>> o=ModelShow1.objects.create(field1='abc')
|
||||||
|
>>> o.m2m.add(o) ; o.save()
|
||||||
|
>>> ModelShow1.objects.all()
|
||||||
|
[ <ModelShow1: id 1, field1 (CharField), m2m (ManyToManyField)> ]
|
||||||
|
|
||||||
|
>>> o=ModelShow2.objects.create(field1='abc')
|
||||||
|
>>> o.m2m.add(o) ; o.save()
|
||||||
|
>>> ModelShow2.objects.all()
|
||||||
|
[ <ModelShow2: id 1, field1: "abc", m2m: 1> ]
|
||||||
|
|
||||||
|
>>> o=ModelShow3.objects.create(field1='abc')
|
||||||
|
>>> o.m2m.add(o) ; o.save()
|
||||||
|
>>> ModelShow3.objects.all()
|
||||||
|
[ <ModelShow3: id 1, field1 (CharField): "abc", m2m (ManyToManyField): 1> ]
|
||||||
|
|
||||||
|
>>> ModelShow1.objects.all().annotate(Count('m2m'))
|
||||||
|
[ <ModelShow1: id 1, field1 (CharField), m2m (ManyToManyField) - Ann: m2m__count (int)> ]
|
||||||
|
>>> ModelShow2.objects.all().annotate(Count('m2m'))
|
||||||
|
[ <ModelShow2: id 1, field1: "abc", m2m: 1 - Ann: m2m__count: "1"> ]
|
||||||
|
>>> ModelShow3.objects.all().annotate(Count('m2m'))
|
||||||
|
[ <ModelShow3: id 1, field1 (CharField): "abc", m2m (ManyToManyField): 1 - Ann: m2m__count (int): "1"> ]
|
||||||
|
|
||||||
|
|
||||||
### extra() method
|
### extra() method
|
||||||
|
|
||||||
>>> Model2A.objects.extra(where=['id IN (2, 3)'])
|
>>> Model2A.objects.extra(where=['id IN (2, 3)'])
|
||||||
|
|
@ -222,6 +283,7 @@ __test__ = {"doctest": """
|
||||||
[ <Model2B: id 2, field1 (CharField), field2 (CharField)>,
|
[ <Model2B: id 2, field1 (CharField), field2 (CharField)>,
|
||||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||||
|
|
||||||
|
|
||||||
### class filtering, instance_of, not_instance_of
|
### class filtering, instance_of, not_instance_of
|
||||||
|
|
||||||
>>> Model2A.objects.instance_of(Model2B)
|
>>> Model2A.objects.instance_of(Model2B)
|
||||||
|
|
@ -246,6 +308,7 @@ __test__ = {"doctest": """
|
||||||
[ <Model2B: id 2, field1 (CharField), field2 (CharField)>,
|
[ <Model2B: id 2, field1 (CharField), field2 (CharField)>,
|
||||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||||
|
|
||||||
|
|
||||||
### get & delete
|
### get & delete
|
||||||
|
|
||||||
>>> oa=Model2A.objects.get(id=2)
|
>>> oa=Model2A.objects.get(id=2)
|
||||||
|
|
@ -257,6 +320,7 @@ __test__ = {"doctest": """
|
||||||
[ <Model2A: id 1, field1 (CharField)>,
|
[ <Model2A: id 1, field1 (CharField)>,
|
||||||
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
<Model2C: id 3, field1 (CharField), field2 (CharField), field3 (CharField)> ]
|
||||||
|
|
||||||
|
|
||||||
### queryset combining
|
### queryset combining
|
||||||
|
|
||||||
>>> o=ModelX.objects.create(field_x='x')
|
>>> o=ModelX.objects.create(field_x='x')
|
||||||
|
|
@ -266,6 +330,7 @@ __test__ = {"doctest": """
|
||||||
[ <ModelX: id 1, field_b (CharField), field_x (CharField)>,
|
[ <ModelX: id 1, field_b (CharField), field_x (CharField)>,
|
||||||
<ModelY: id 2, field_b (CharField), field_y (CharField)> ]
|
<ModelY: id 2, field_b (CharField), field_y (CharField)> ]
|
||||||
|
|
||||||
|
|
||||||
### multiple inheritance, subclassing third party models (mix PolymorphicModel with models.Model)
|
### multiple inheritance, subclassing third party models (mix PolymorphicModel with models.Model)
|
||||||
|
|
||||||
>>> o = Enhance_Base.objects.create(field_b='b-base')
|
>>> o = Enhance_Base.objects.create(field_b='b-base')
|
||||||
|
|
@ -275,6 +340,7 @@ __test__ = {"doctest": """
|
||||||
[ <Enhance_Base: id 1, field_b (CharField): "b-base">,
|
[ <Enhance_Base: id 1, field_b (CharField): "b-base">,
|
||||||
<Enhance_Inherit: id 2, field_b (CharField): "b-inherit", field_p (CharField): "p", field_i (CharField): "i"> ]
|
<Enhance_Inherit: id 2, field_b (CharField): "b-inherit", field_p (CharField): "p", field_i (CharField): "i"> ]
|
||||||
|
|
||||||
|
|
||||||
### ForeignKey, ManyToManyField
|
### ForeignKey, ManyToManyField
|
||||||
|
|
||||||
>>> obase=RelationBase.objects.create(field_base='base')
|
>>> obase=RelationBase.objects.create(field_base='base')
|
||||||
|
|
@ -284,27 +350,27 @@ __test__ = {"doctest": """
|
||||||
>>> oa.m2m.add(oa); oa.m2m.add(ob)
|
>>> oa.m2m.add(oa); oa.m2m.add(ob)
|
||||||
|
|
||||||
>>> RelationBase.objects.all()
|
>>> RelationBase.objects.all()
|
||||||
[ <RelationBase: id 1, field_base (CharField): "base", fk (ForeignKey): "None">,
|
[ <RelationBase: id 1, field_base (CharField): "base", fk (ForeignKey): "None", m2m (ManyToManyField): 0>,
|
||||||
<RelationA: id 2, field_base (CharField): "A1", fk (ForeignKey): "RelationBase", field_a (CharField): "A2">,
|
<RelationA: id 2, field_base (CharField): "A1", fk (ForeignKey): "RelationBase", field_a (CharField): "A2", m2m (ManyToManyField): 2>,
|
||||||
<RelationB: id 3, field_base (CharField): "B1", fk (ForeignKey): "RelationA", field_b (CharField): "B2">,
|
<RelationB: id 3, field_base (CharField): "B1", fk (ForeignKey): "RelationA", field_b (CharField): "B2", m2m (ManyToManyField): 1>,
|
||||||
<RelationBC: id 4, field_base (CharField): "C1", fk (ForeignKey): "RelationA", field_b (CharField): "C2", field_c (CharField): "C3"> ]
|
<RelationBC: id 4, field_base (CharField): "C1", fk (ForeignKey): "RelationA", field_b (CharField): "C2", field_c (CharField): "C3", m2m (ManyToManyField): 0> ]
|
||||||
|
|
||||||
>>> oa=RelationBase.objects.get(id=2)
|
>>> oa=RelationBase.objects.get(id=2)
|
||||||
>>> oa.fk
|
>>> oa.fk
|
||||||
<RelationBase: id 1, field_base (CharField): "base", fk (ForeignKey): "None">
|
<RelationBase: id 1, field_base (CharField): "base", fk (ForeignKey): "None", m2m (ManyToManyField): 0>
|
||||||
|
|
||||||
>>> oa.relationbase_set.all()
|
>>> oa.relationbase_set.all()
|
||||||
[ <RelationB: id 3, field_base (CharField): "B1", fk (ForeignKey): "RelationA", field_b (CharField): "B2">,
|
[ <RelationB: id 3, field_base (CharField): "B1", fk (ForeignKey): "RelationA", field_b (CharField): "B2", m2m (ManyToManyField): 1>,
|
||||||
<RelationBC: id 4, field_base (CharField): "C1", fk (ForeignKey): "RelationA", field_b (CharField): "C2", field_c (CharField): "C3"> ]
|
<RelationBC: id 4, field_base (CharField): "C1", fk (ForeignKey): "RelationA", field_b (CharField): "C2", field_c (CharField): "C3", m2m (ManyToManyField): 0> ]
|
||||||
|
|
||||||
>>> ob=RelationBase.objects.get(id=3)
|
>>> ob=RelationBase.objects.get(id=3)
|
||||||
>>> ob.fk
|
>>> ob.fk
|
||||||
<RelationA: id 2, field_base (CharField): "A1", fk (ForeignKey): "RelationBase", field_a (CharField): "A2">
|
<RelationA: id 2, field_base (CharField): "A1", fk (ForeignKey): "RelationBase", field_a (CharField): "A2", m2m (ManyToManyField): 2>
|
||||||
|
|
||||||
>>> oa=RelationA.objects.get()
|
>>> oa=RelationA.objects.get()
|
||||||
>>> oa.m2m.all()
|
>>> oa.m2m.all()
|
||||||
[ <RelationA: id 2, field_base (CharField): "A1", fk (ForeignKey): "RelationBase", field_a (CharField): "A2">,
|
[ <RelationA: id 2, field_base (CharField): "A1", fk (ForeignKey): "RelationBase", field_a (CharField): "A2", m2m (ManyToManyField): 2>,
|
||||||
<RelationB: id 3, field_base (CharField): "B1", fk (ForeignKey): "RelationA", field_b (CharField): "B2"> ]
|
<RelationB: id 3, field_base (CharField): "B1", fk (ForeignKey): "RelationA", field_b (CharField): "B2", m2m (ManyToManyField): 1> ]
|
||||||
|
|
||||||
### user-defined manager
|
### user-defined manager
|
||||||
|
|
||||||
|
|
@ -320,6 +386,7 @@ __test__ = {"doctest": """
|
||||||
>>> type(ModelWithMyManager._default_manager)
|
>>> type(ModelWithMyManager._default_manager)
|
||||||
<class 'polymorphic.tests.MyManager'>
|
<class 'polymorphic.tests.MyManager'>
|
||||||
|
|
||||||
|
|
||||||
### Manager Inheritance
|
### Manager Inheritance
|
||||||
|
|
||||||
>>> type(MRODerived.objects) # MRO
|
>>> type(MRODerived.objects) # MRO
|
||||||
|
|
@ -333,10 +400,12 @@ __test__ = {"doctest": """
|
||||||
>>> type(MROBase2._default_manager)
|
>>> type(MROBase2._default_manager)
|
||||||
<class 'polymorphic.tests.MyManager'>
|
<class 'polymorphic.tests.MyManager'>
|
||||||
|
|
||||||
|
|
||||||
### fixed issue in PolymorphicModel.__getattribute__: field name same as model name
|
### fixed issue in PolymorphicModel.__getattribute__: field name same as model name
|
||||||
>>> ModelFieldNameTest.objects.create(modelfieldnametest='1')
|
>>> ModelFieldNameTest.objects.create(modelfieldnametest='1')
|
||||||
<ModelFieldNameTest: id 1, modelfieldnametest (CharField)>
|
<ModelFieldNameTest: id 1, modelfieldnametest (CharField)>
|
||||||
|
|
||||||
|
|
||||||
### fixed issue in PolymorphicModel.__getattribute__:
|
### fixed issue in PolymorphicModel.__getattribute__:
|
||||||
# if subclass defined __init__ and accessed class members, __getattribute__ had a problem: "...has no attribute 'sub_and_superclass_dict'"
|
# if subclass defined __init__ and accessed class members, __getattribute__ had a problem: "...has no attribute 'sub_and_superclass_dict'"
|
||||||
#>>> o
|
#>>> o
|
||||||
|
|
@ -344,6 +413,7 @@ __test__ = {"doctest": """
|
||||||
>>> o.bar
|
>>> o.bar
|
||||||
'XYZ'
|
'XYZ'
|
||||||
|
|
||||||
|
|
||||||
### Django model inheritance diamond problem, fails for Django 1.1
|
### Django model inheritance diamond problem, fails for Django 1.1
|
||||||
|
|
||||||
#>>> o=DiamondXY.objects.create(field_b='b', field_x='x', field_y='y')
|
#>>> o=DiamondXY.objects.create(field_b='b', field_x='x', field_y='y')
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue