/polymorphic/showfields.py

https://bitbucket.org/bconstantin/django_polymorphic/ · Python · 150 lines · 108 code · 30 blank · 12 comment · 35 complexity · c2b34d6964245a09fd7566fe716d18db MD5 · raw file

  1. # -*- coding: utf-8 -*-
  2. from django.db import models
  3. from pprint import pformat
  4. class ShowFieldBase(object):
  5. """ base class for the ShowField... model mixins, does the work """
  6. polymorphic_query_multiline_output = True # cause nicer multiline PolymorphicQuery output
  7. polymorphic_showfield_type = False
  8. polymorphic_showfield_content = False
  9. # these may be overridden by the user
  10. polymorphic_showfield_max_line_width = None
  11. polymorphic_showfield_max_field_width = 20
  12. polymorphic_showfield_old_format = False
  13. def __repr__(self):
  14. return self.__unicode__()
  15. def _showfields_get_content(self, field_name, field_type=type(None)):
  16. "helper for __unicode__"
  17. content = getattr(self, field_name)
  18. if self.polymorphic_showfield_old_format: out = ': '
  19. else: out = ' '
  20. if issubclass(field_type, models.ForeignKey):
  21. if content is None: out += 'None'
  22. else: out += content.__class__.__name__
  23. elif issubclass(field_type, models.ManyToManyField):
  24. out += '%d' % content.count()
  25. elif type(content) in (int,long):
  26. out += unicode(content)
  27. elif content is None:
  28. out += 'None'
  29. else:
  30. txt=unicode(content)
  31. if len(txt)>self.polymorphic_showfield_max_field_width:
  32. txt=txt[:self.polymorphic_showfield_max_field_width-2]+'..'
  33. out += '"' + txt + '"'
  34. return out
  35. def _showfields_add_regular_fields(self, parts):
  36. "helper for __unicode__"
  37. done_fields = set()
  38. for field in self._meta.fields + self._meta.many_to_many:
  39. if field.name in self.polymorphic_internal_model_fields or '_ptr' in field.name: continue
  40. if field.name in done_fields: continue # work around django diamond inheritance problem
  41. done_fields.add(field.name)
  42. out = field.name
  43. # if this is the standard primary key named "id", print it as we did with older versions of django_polymorphic
  44. if field.primary_key and field.name=='id' and type(field)==models.AutoField:
  45. out += ' '+ unicode(getattr(self, field.name))
  46. # otherwise, display it just like all other fields (with correct type, shortened content etc.)
  47. else:
  48. if self.polymorphic_showfield_type:
  49. out += ' (' + type(field).__name__
  50. if field.primary_key: out += '/pk'
  51. out += ')'
  52. if self.polymorphic_showfield_content:
  53. out += self._showfields_get_content(field.name,type(field))
  54. parts.append((False, out,','))
  55. def _showfields_add_dynamic_fields(self, field_list, title, parts):
  56. "helper for __unicode__"
  57. parts.append( ( True, '- '+title, ':' ) )
  58. for field_name in field_list:
  59. out = field_name
  60. content = getattr(self, field_name)
  61. if self.polymorphic_showfield_type:
  62. out += ' (' + type(content).__name__ + ')'
  63. if self.polymorphic_showfield_content:
  64. out += self._showfields_get_content(field_name)
  65. parts.append( ( False, out, ',' ) )
  66. def __unicode__(self):
  67. # create list ("parts") containing one tuple for each title/field:
  68. # ( bool: new section , item-text , separator to use after item )
  69. # start with model name
  70. parts = [ (True, self.__class__.__name__, ':') ]
  71. # add all regular fields
  72. self._showfields_add_regular_fields(parts)
  73. # add annotate fields
  74. if hasattr(self,'polymorphic_annotate_names'):
  75. self._showfields_add_dynamic_fields(self.polymorphic_annotate_names, 'Ann', parts)
  76. # add extra() select fields
  77. if hasattr(self,'polymorphic_extra_select_names'):
  78. self._showfields_add_dynamic_fields(self.polymorphic_extra_select_names, 'Extra', parts)
  79. # format result
  80. indent = len(self.__class__.__name__)+5
  81. indentstr = ''.rjust(indent)
  82. out=u''; xpos=0; possible_line_break_pos = None
  83. for i in xrange(len(parts)):
  84. new_section, p, separator = parts[i]
  85. final = (i==len(parts)-1)
  86. if not final:
  87. next_new_section, _, _ = parts[i+1]
  88. if ( self.polymorphic_showfield_max_line_width
  89. and xpos+len(p) > self.polymorphic_showfield_max_line_width
  90. and possible_line_break_pos!=None ):
  91. rest = out[possible_line_break_pos:]
  92. out = out[:possible_line_break_pos]
  93. out+= '\n'+indentstr+rest
  94. xpos=indent+len(rest)
  95. out += p; xpos += len(p)
  96. if not final:
  97. if not next_new_section:
  98. out += separator; xpos += len(separator)
  99. out += ' '; xpos += 1
  100. if not new_section:
  101. possible_line_break_pos=len(out)
  102. return u'<'+out+'>'
  103. class ShowFieldType(ShowFieldBase):
  104. """ model mixin that shows the object's class and it's field types """
  105. polymorphic_showfield_type = True
  106. class ShowFieldContent(ShowFieldBase):
  107. """ model mixin that shows the object's class, it's fields and field contents """
  108. polymorphic_showfield_content = True
  109. class ShowFieldTypeAndContent(ShowFieldBase):
  110. """ model mixin, like ShowFieldContent, but also show field types """
  111. polymorphic_showfield_type = True
  112. polymorphic_showfield_content = True
  113. # compatibility with old class names
  114. ShowFieldTypes = ShowFieldType
  115. ShowFields = ShowFieldContent
  116. ShowFieldsAndTypes = ShowFieldTypeAndContent