improved showfields.py for better and more precise output, updated tests

fix_request_path_info
Bert Constantin 2010-10-31 12:27:21 +01:00
parent a4ac6cc91d
commit 52f32c1fc3
4 changed files with 247 additions and 102 deletions

View File

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
"""
This module is a scratchpad for general development, testing & debugging
"""
import uuid
from django.core.management.base import NoArgsCommand
from django.db.models import connection
from pprint import pprint
import settings
from pexp.models import *
def reset_queries():
connection.queries=[]
def show_queries():
print; print 'QUERIES:',len(connection.queries); pprint(connection.queries); print; connection.queries=[]
class Command(NoArgsCommand):
help = ""
def handle_noargs(self, **options):
print 'polycmd - sqlite test db is stored in:',settings.SQLITE_DB_PATH
print
Project.objects.all().delete()
a=Project.objects.create(topic="John's gathering")
b=ArtProject.objects.create(topic="Sculpting with Tim", artist="T. Turner")
c=ResearchProject.objects.create(topic="Swallow Aerodynamics", supervisor="Dr. Winter")
print Project.objects.all()
print
ModelA.objects.all().delete()
a=ModelA.objects.create(field1='A1')
b=ModelB.objects.create(field1='B1', field2='B2')
c=ModelC.objects.create(field1='C1', field2='C2', field3='C3')
print ModelA.objects.extra( select={"select1": "field1 = 'A1'", "select2": "field1 = 'A0'"} )
print
if not 'UUIDField' in globals(): return
UUIDModelA.objects.all().delete()
a=UUIDModelA.objects.create(field1='012345678900123456789001234567890012345678900123456789001234567890')
b=UUIDModelB.objects.create(field1='B1', field2='B2')
c=UUIDModelC.objects.create(field1='C1', field2='C2', field3='C3')
print UUIDModelA.objects.all()

View File

@ -39,3 +39,13 @@ if not (django_VERSION[0]<=1 and django_VERSION[1]<=1):
class Model2C(Model2B): class Model2C(Model2B):
field3 = models.CharField(max_length=10) field3 = models.CharField(max_length=10)
try: from polymorphic.test_tools import UUIDField
except: pass
if 'UUIDField' in globals():
class UUIDModelA(ShowFieldTypeAndContent, PolymorphicModel):
uuid_primary_key = UUIDField(primary_key = True)
field1 = models.CharField(max_length=10)
class UUIDModelB(UUIDModelA):
field2 = models.CharField(max_length=10)
class UUIDModelC(UUIDModelB):
field3 = models.CharField(max_length=10)

View File

@ -1,64 +1,134 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from django.db import models from django.db import models
from pprint import pformat
class ShowFieldBase(object): class ShowFieldBase(object):
""" base class for the ShowField... model mixins, does the work """ """ base class for the ShowField... model mixins, does the work """
polymorphic_query_multiline_output = True # cause nicer multiline PolymorphicQuery output polymorphic_query_multiline_output = True # cause nicer multiline PolymorphicQuery output
polymorphic_showfield_type = False polymorphic_showfield_type = False
polymorphic_showfield_content = False polymorphic_showfield_content = False
# these may be overridden by the user
polymorphic_showfield_max_line_width = None
polymorphic_showfield_max_field_width = 20
polymorphic_showfield_old_format = False
def __repr__(self): def __repr__(self):
return self.__unicode__() return self.__unicode__()
def __unicode__(self): def _showfields_get_content(self, field_name, field_type=type(None)):
out = u'<'+self.__class__.__name__+': id %s' % unicode(self.pk) "helper for __unicode__"
for f in self._meta.fields + self._meta.many_to_many: content = getattr(self, field_name)
if self.polymorphic_showfield_old_format: out = ': '
if f.name in [ 'id' ] + self.polymorphic_internal_model_fields or 'ptr' in f.name: continue else: out = ' '
out += ', ' + f.name if issubclass(field_type, models.ForeignKey):
if content is None: out += 'None'
if self.polymorphic_showfield_type: else: out += content.__class__.__name__
out += ' (' + type(f).__name__ + ')' elif issubclass(field_type, models.ManyToManyField):
out += '%d' % content.count()
if self.polymorphic_showfield_content: elif type(content) in (int,long):
o = getattr(self, f.name) out += unicode(content)
elif content is None:
if isinstance(f, (models.ForeignKey)): out += 'None'
#out += ': ' + ( '"None"' if o is None else '"' + o.__class__.__name__ + '"' )
out += ': '
if o is None:
out += '"None"'
else: else:
out += '"' + o.__class__.__name__ + '"' txt=unicode(content)
if len(txt)>self.polymorphic_showfield_max_field_width:
elif isinstance(f, (models.ManyToManyField)): txt=txt[:self.polymorphic_showfield_max_field_width-2]+'..'
out += ': %d' % o.count() out += '"' + txt + '"'
else:
out += ': "' + unicode(o) + '"'
def get_dynamic_fields(field_list, title):
out = ' - '+title+': '
for an in field_list:
if an != field_list[0]:
out += ', '
out += an
if self.polymorphic_showfield_type:
out += ' (' + type(getattr(self, an)).__name__ + ')'
if self.polymorphic_showfield_content:
out += ': "' + unicode(getattr(self, an)) + '"'
return out return out
def _showfields_add_regular_fields(self, parts):
"helper for __unicode__"
done_fields = set()
for field in self._meta.fields + self._meta.many_to_many:
if field.name in self.polymorphic_internal_model_fields or '_ptr' in field.name: continue
if field.name in done_fields: continue # work around django diamond inheritance problem
done_fields.add(field.name)
out = field.name
# if this is the standard primary key named "id", print it as we did with older versions of django_polymorphic
if field.primary_key and field.name=='id' and type(field)==models.AutoField:
out += ' '+ unicode(getattr(self, field.name))
# otherwise, display it just like all other fields (with correct type, shortened content etc.)
else:
if self.polymorphic_showfield_type:
out += ' (' + type(field).__name__
if field.primary_key: out += '/pk'
out += ')'
if self.polymorphic_showfield_content:
out += self._showfields_get_content(field.name,type(field))
parts.append((False, out,','))
def _showfields_add_dynamic_fields(self, field_list, title, parts):
"helper for __unicode__"
parts.append( ( True, '- '+title, ':' ) )
for field_name in field_list:
out = field_name
content = getattr(self, field_name)
if self.polymorphic_showfield_type:
out += ' (' + type(content).__name__ + ')'
if self.polymorphic_showfield_content:
out += self._showfields_get_content(field_name)
parts.append( ( False, out, ',' ) )
def __unicode__(self):
# create list ("parts") containing one tuple for each title/field:
# ( bool: new section , item-text , separator to use after item )
# start with model name
parts = [ (True, self.__class__.__name__, ':') ]
# add all regular fields
self._showfields_add_regular_fields(parts)
# add annotate fields
if hasattr(self,'polymorphic_annotate_names'): if hasattr(self,'polymorphic_annotate_names'):
out+=get_dynamic_fields(self.polymorphic_annotate_names, 'Ann') self._showfields_add_dynamic_fields(self.polymorphic_annotate_names, 'Ann', parts)
# add extra() select fields
if hasattr(self,'polymorphic_extra_select_names'): if hasattr(self,'polymorphic_extra_select_names'):
out+=get_dynamic_fields(self.polymorphic_extra_select_names, 'Extra') self._showfields_add_dynamic_fields(self.polymorphic_extra_select_names, 'Extra', parts)
# format result
indent = len(self.__class__.__name__)+5
indentstr = ''.rjust(indent)
out=u''; xpos=0; possible_line_break_pos = None
for i in xrange(len(parts)):
new_section, p, separator = parts[i]
final = (i==len(parts)-1)
if not final:
next_new_section, _, _ = parts[i+1]
if ( self.polymorphic_showfield_max_line_width
and xpos+len(p) > self.polymorphic_showfield_max_line_width
and possible_line_break_pos!=None ):
rest = out[possible_line_break_pos:]
out = out[:possible_line_break_pos]
out+= '\n'+indentstr+rest
xpos=indent+len(rest)
out += p; xpos += len(p)
if not final:
if not next_new_section:
out += separator; xpos += len(separator)
out += ' '; xpos += 1
if not new_section:
possible_line_break_pos=len(out)
return u'<'+out+'>'
return out+'>'
class ShowFieldType(ShowFieldBase): class ShowFieldType(ShowFieldBase):
""" model mixin that shows the object's class and it's field types """ """ model mixin that shows the object's class and it's field types """

View File

@ -5,13 +5,14 @@
import settings import settings
import sys import sys
from pprint import pprint
from django import VERSION as django_VERSION
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,Count 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 from polymorphic import PolymorphicModel, PolymorphicManager, PolymorphicQuerySet
from polymorphic import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent, get_version from polymorphic import ShowFieldContent, ShowFieldType, ShowFieldTypeAndContent, get_version
@ -155,18 +156,29 @@ class InitTestModelSubclass(InitTestModel):
def x(self): def x(self):
return 'XYZ' return 'XYZ'
# 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.test_tools import UUIDField
except: pass except: pass
if 'UUIDField' in globals(): if 'UUIDField' in globals():
import uuid import uuid
class UUIDProject(ShowFieldTypeAndContent, PolymorphicModel): class UUIDProject(ShowFieldTypeAndContent, PolymorphicModel):
id = UUIDField(primary_key = True) uuid_primary_key = UUIDField(primary_key = True)
topic = models.CharField(max_length = 30) topic = models.CharField(max_length = 30)
class UUIDArtProject(UUIDProject): class UUIDArtProject(UUIDProject):
artist = models.CharField(max_length = 30) artist = models.CharField(max_length = 30)
class UUIDResearchProject(UUIDProject): class UUIDResearchProject(UUIDProject):
supervisor = models.CharField(max_length = 30) supervisor = models.CharField(max_length = 30)
class UUIDPlainA(models.Model):
uuid_primary_key = UUIDField(primary_key = True)
field1 = models.CharField(max_length=10)
class UUIDPlainB(UUIDPlainA):
field2 = models.CharField(max_length=10)
class UUIDPlainC(UUIDPlainB):
field3 = models.CharField(max_length=10)
# test bad field name # test bad field name
@ -226,14 +238,14 @@ class testclass(TestCase):
### test ordering for field in all entries ### 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">,
<BlogB: id 2, name (CharField): "Bb1">, <BlogB: id 2, name (CharField) "Bb1">,
<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">,
<BlogA: id 5, name (CharField): "B2", info (CharField): "i2">, <BlogA: id 5, name (CharField) "B2", info (CharField) "i2">,
<BlogA: id 1, name (CharField): "B1", info (CharField): "i1"> ]''' <BlogA: id 1, name (CharField) "B1", info (CharField) "i1"> ]'''
x = '\n' + repr(BlogBase.objects.order_by('-name')) x = '\n' + repr(BlogBase.objects.order_by('-name'))
assert x == expected assert x == expected
@ -241,25 +253,25 @@ class testclass(TestCase):
# MySQL and SQLite return this order # MySQL and SQLite return this order
expected1=''' 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">,
<BlogA: id 5, name (CharField): "B2", info (CharField): "i2">, <BlogA: id 5, name (CharField) "B2", info (CharField) "i2">,
<BlogA: id 1, name (CharField): "B1", info (CharField): "i1">, <BlogA: id 1, name (CharField) "B1", info (CharField) "i1">,
<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 # PostgreSQL returns this order
expected2=''' expected2='''
[ <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">,
<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">,
<BlogA: id 5, name (CharField): "B2", info (CharField): "i2">, <BlogA: id 5, name (CharField) "B2", info (CharField) "i2">,
<BlogA: id 1, name (CharField): "B1", info (CharField): "i1"> ]''' <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 == expected1 or x == expected2 assert x == expected1 or x == expected2
@ -287,17 +299,25 @@ class testclass(TestCase):
b=qs[1] b=qs[1]
c=qs[2] c=qs[2]
assert len(qs)==3 assert len(qs)==3
assert type(a.id)==uuid.UUID and type(a.pk)==uuid.UUID assert type(a.uuid_primary_key)==uuid.UUID and type(a.pk)==uuid.UUID
res=repr(qs) res=repr(qs)
import re import re
res=re.sub(' id ...................................., topic',' id, topic',res) res=re.sub(' "(.*?)..", topic',', topic',res)
res_exp="""[ <UUIDProject: id, topic (CharField): "John's gathering">, res_exp="""[ <UUIDProject: uuid_primary_key (UUIDField/pk), topic (CharField) "John's gathering">,
<UUIDArtProject: id, topic (CharField): "Sculpting with Tim", artist (CharField): "T. Turner">, <UUIDArtProject: uuid_primary_key (UUIDField/pk), topic (CharField) "Sculpting with Tim", artist (CharField) "T. Turner">,
<UUIDResearchProject: id, topic (CharField): "Swallow Aerodynamics", supervisor (CharField): "Dr. Winter"> ]""" <UUIDResearchProject: uuid_primary_key (UUIDField/pk), topic (CharField) "Swallow Aerodynamics", supervisor (CharField) "Dr. Winter"> ]"""
assert res==res_exp assert res==res_exp, res
#if (a.pk!= uuid.UUID or c.pk!= uuid.UUID):
# print
# print '# known inconstency with custom primary key field detected (django problem?)'
a=UUIDPlainA.objects.create(field1='A1')
b=UUIDPlainB.objects.create(field1='B1', field2='B2')
c=UUIDPlainC.objects.create(field1='C1', field2='C2', field3='C3')
qs=UUIDPlainA.objects.all()
if (a.pk!= uuid.UUID or c.pk!= uuid.UUID): if (a.pk!= uuid.UUID or c.pk!= uuid.UUID):
print print
print '# known django object inconstency with custom primary key field detected' print '# known type inconstency with custom primary key field detected (django problem?)'
def show_base_manager(model): def show_base_manager(model):
@ -401,19 +421,19 @@ __test__ = {"doctest": """
>>> o=ModelShow2.objects.create(field1='abc') >>> o=ModelShow2.objects.create(field1='abc')
>>> o.m2m.add(o) ; o.save() >>> o.m2m.add(o) ; o.save()
>>> ModelShow2.objects.all() >>> ModelShow2.objects.all()
[ <ModelShow2: id 1, field1: "abc", m2m: 1> ] [ <ModelShow2: id 1, field1 "abc", m2m 1> ]
>>> o=ModelShow3.objects.create(field1='abc') >>> o=ModelShow3.objects.create(field1='abc')
>>> o.m2m.add(o) ; o.save() >>> o.m2m.add(o) ; o.save()
>>> ModelShow3.objects.all() >>> ModelShow3.objects.all()
[ <ModelShow3: id 1, field1 (CharField): "abc", m2m (ManyToManyField): 1> ] [ <ModelShow3: id 1, field1 (CharField) "abc", m2m (ManyToManyField) 1> ]
>>> ModelShow1.objects.all().annotate(Count('m2m')) >>> ModelShow1.objects.all().annotate(Count('m2m'))
[ <ModelShow1: id 1, field1 (CharField), m2m (ManyToManyField) - Ann: m2m__count (int)> ] [ <ModelShow1: id 1, field1 (CharField), m2m (ManyToManyField) - Ann: m2m__count (int)> ]
>>> ModelShow2.objects.all().annotate(Count('m2m')) >>> ModelShow2.objects.all().annotate(Count('m2m'))
[ <ModelShow2: id 1, field1: "abc", m2m: 1 - Ann: m2m__count: "1"> ] [ <ModelShow2: id 1, field1 "abc", m2m 1 - Ann: m2m__count 1> ]
>>> ModelShow3.objects.all().annotate(Count('m2m')) >>> ModelShow3.objects.all().annotate(Count('m2m'))
[ <ModelShow3: id 1, field1 (CharField): "abc", m2m (ManyToManyField): 1 - Ann: m2m__count (int): "1"> ] [ <ModelShow3: id 1, field1 (CharField) "abc", m2m (ManyToManyField) 1 - Ann: m2m__count (int) 1> ]
# no pretty printing # no pretty printing
>>> o=ModelShow1_plain.objects.create(field1='abc') >>> o=ModelShow1_plain.objects.create(field1='abc')
@ -439,10 +459,9 @@ __test__ = {"doctest": """
>>> o=ModelExtraExternal.objects.create(topic='extra2') >>> o=ModelExtraExternal.objects.create(topic='extra2')
>>> o=ModelExtraExternal.objects.create(topic='extra3') >>> o=ModelExtraExternal.objects.create(topic='extra3')
>>> ModelExtraA.objects.extra(tables=["polymorphic_modelextraexternal"], select={"topic":"polymorphic_modelextraexternal.topic"}, where=["polymorphic_modelextraa.id = polymorphic_modelextraexternal.id"] ) >>> ModelExtraA.objects.extra(tables=["polymorphic_modelextraexternal"], select={"topic":"polymorphic_modelextraexternal.topic"}, where=["polymorphic_modelextraa.id = polymorphic_modelextraexternal.id"] )
[ <ModelExtraA: id 1, field1 (CharField): "A1" - Extra: topic (unicode): "extra1">, [ <ModelExtraA: id 1, field1 (CharField) "A1" - Extra: topic (unicode) "extra1">,
<ModelExtraB: id 2, field1 (CharField): "B1", field2 (CharField): "B2" - Extra: topic (unicode): "extra2">, <ModelExtraB: id 2, field1 (CharField) "B1", field2 (CharField) "B2" - Extra: topic (unicode) "extra2">,
<ModelExtraC: id 3, field1 (CharField): "C1", field2 (CharField): "C2", field3 (CharField): "C3" - Extra: topic (unicode): "extra3"> ] <ModelExtraC: id 3, field1 (CharField) "C1", field2 (CharField) "C2", field3 (CharField) "C3" - Extra: topic (unicode) "extra3"> ]
### class filtering, instance_of, not_instance_of ### class filtering, instance_of, not_instance_of
@ -501,8 +520,8 @@ __test__ = {"doctest": """
>>> o = Enhance_Inherit.objects.create(field_b='b-inherit', field_p='p', field_i='i') >>> o = Enhance_Inherit.objects.create(field_b='b-inherit', field_p='p', field_i='i')
>>> Enhance_Base.objects.all() >>> Enhance_Base.objects.all()
[ <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
@ -514,27 +533,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", m2m (ManyToManyField): 0>, [ <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", m2m (ManyToManyField): 2>, <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", m2m (ManyToManyField): 1>, <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", m2m (ManyToManyField): 0> ] <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", m2m (ManyToManyField): 0> <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", m2m (ManyToManyField): 1>, [ <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", m2m (ManyToManyField): 0> ] <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", m2m (ManyToManyField): 2> <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", m2m (ManyToManyField): 2>, [ <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", m2m (ManyToManyField): 1> ] <RelationB: id 3, field_base (CharField) "B1", fk (ForeignKey) RelationA, field_b (CharField) "B2", m2m (ManyToManyField) 1> ]
### user-defined manager ### user-defined manager
@ -542,8 +561,8 @@ __test__ = {"doctest": """
>>> o=ModelWithMyManager.objects.create(field1='D1b', field4='D4b') >>> o=ModelWithMyManager.objects.create(field1='D1b', field4='D4b')
>>> ModelWithMyManager.objects.all() >>> ModelWithMyManager.objects.all()
[ <ModelWithMyManager: id 6, field1 (CharField): "D1b", field4 (CharField): "D4b">, [ <ModelWithMyManager: id 6, field1 (CharField) "D1b", field4 (CharField) "D4b">,
<ModelWithMyManager: id 5, field1 (CharField): "D1a", field4 (CharField): "D4a"> ] <ModelWithMyManager: id 5, field1 (CharField) "D1a", field4 (CharField) "D4a"> ]
>>> type(ModelWithMyManager.objects) >>> type(ModelWithMyManager.objects)
<class 'polymorphic.tests.MyManager'> <class 'polymorphic.tests.MyManager'>