No Description

tables2_columns.py 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. from django.core.exceptions import ImproperlyConfigured
  2. from django.utils.safestring import mark_safe
  3. from django.utils.formats import date_format, time_format
  4. from django.utils.timezone import localtime
  5. from django_tables2 import Column
  6. from django_tables2.columns import library
  7. from django_tables2.columns.linkcolumn import BaseLinkColumn
  8. from django_tables2.utils import Accessor
  9. from viewsets import CrudViewset
  10. import six
  11. import pytz
  12. import urllib
  13. #import logging
  14. #logger = logging.getLogger('console')
  15. def render_image_column(url, width=None, height=None, max_width=None, max_height=None, allow_shrink=True, background_position='center', background_size='contain'):
  16. if max_width is not None:
  17. if max_height is not None:
  18. if not allow_shrink or (width is None) or (height is None):
  19. width = max_width
  20. height = max_height
  21. elif (width > max_width) or (height > max_height):
  22. if width * max_height > height * max_width:
  23. height = height * max_width / width
  24. width = max_width
  25. else:
  26. width = width * max_height / height
  27. height = max_height
  28. elif (width is not None) and ((width > max_width) or not allow_shrink):
  29. height = height * max_width / width
  30. width = max_width
  31. elif max_height is not None:
  32. if (height is not None) and ((height > max_height) or not allow_shrink):
  33. width = width * max_height / height
  34. height = max_height
  35. if (width is None) or (height is None):
  36. raise ImproperlyConfigured('Insufficient information to determine image width and height')
  37. return mark_safe('<div style="width:%dpx;height:%dpx;background:url(%s) no-repeat;background-position: %s; background-size: %s;"></div>' % (width, height, url, urllib.quote(background_position), urllib.quote(background_size)))
  38. @library.register
  39. class ImageColumn(Column):
  40. def __init__(self, width_accessor=None, height_accessor=None, max_width=None, max_height=None, allow_shrink=True, background_size='contain', background_position='center', **extra):
  41. super(ImageColumn, self).__init__(**extra)
  42. if not (width_accessor is None or isinstance(width_accessor, six.string_types) or callable(width_accessor)):
  43. raise TypeError('width_accessor must be a string or callable, not %s' % type(accessor).__name__)
  44. if not (height_accessor is None or isinstance(height_accessor, six.string_types) or callable(height_accessor)):
  45. raise TypeError('height_accessor must be a string or callable, not %s' % type(accessor).__name__)
  46. self.width_accessor = Accessor(width_accessor) if width_accessor else None
  47. self.height_accessor = Accessor(height_accessor) if height_accessor else None
  48. self.max_width = max_width
  49. self.max_height = max_height
  50. self.allow_shrink = allow_shrink
  51. self.background_size = background_size
  52. self.background_position = background_position
  53. def render(self, record, value, bound_column):
  54. width = None if self.width_accessor is None else self.width_accessor.resolve(record)
  55. height = None if self.height_accessor is None else self.height_accessor.resolve(record)
  56. return render_image_column(value.url, width=width, height=height, max_width=self.max_width, max_height=self.max_height, allow_shrink=self.allow_shrink, background_position=self.background_position, background_size=self.background_size)
  57. class DateTimeColumnBase(Column):
  58. def __init__(self, format=None, short=True, timezone=None, use_user_timezone=False, timezone_accessor=None, **extra):
  59. super(DateTimeColumnBase, self).__init__(**extra)
  60. if not (timezone_accessor is None or isinstance(timezone_accessor, six.string_types) or callable(timezone_accessor)):
  61. raise TypeError('timezone_accessor must be a string or callable, not %s' % type(accessor).__name__)
  62. self.timezone = timezone
  63. self.use_user_timezone = use_user_timezone
  64. self.timezone_accessor = Accessor(timezone_accessor) if timezone_accessor else None
  65. if format is None:
  66. if short:
  67. if self.SHORT_FORMAT is None:
  68. raise ImproperlyConfigured('%s does not provide a short format' % self.__class__.__name__)
  69. self.format = self.SHORT_FORMAT
  70. else:
  71. self.format = self.LONG_FORMAT
  72. else:
  73. self.format = format
  74. def convert_value(self, record, value, bound_column):
  75. if self.timezone is not None:
  76. tz = self.timezone
  77. elif self.use_user_timezone:
  78. tz = pytz.timezone(bound_column._table.view.request.user.time_zone())
  79. elif self.timezone_accessor is not None:
  80. tz = pytz.timezone(self.timezone_accessor.resolve(record))
  81. else:
  82. # Default to Django's idea of local time
  83. tz = None
  84. return localtime(value, tz)
  85. @library.register
  86. class CrudLinkColumn(BaseLinkColumn):
  87. def __init__(self, view_type=None, attrs=None, **extra):
  88. super(CrudLinkColumn, self).__init__(attrs, **extra)
  89. self.view_type = view_type
  90. def render(self, record, value, bound_column):
  91. table = bound_column._table
  92. return self.render_link(
  93. table.viewset.get_view_url(table.viewset.instance_breadcrumb_view_type if self.view_type is None else self.view_type, table.view, table.GET, record),
  94. record=record,
  95. value=value
  96. )
  97. @library.register
  98. class CrudRelativeLinkColumn(BaseLinkColumn):
  99. def __init__(self, url_name_suffix, kwargs_callable=None, pk_url_kwarg=None, remove_url_name_components=0, attrs=None, **extra):
  100. super(CrudRelativeLinkColumn, self).__init__(attrs, **extra)
  101. self.url_name_suffix = url_name_suffix
  102. self.kwargs_callable = kwargs_callable
  103. self.pk_url_kwarg = pk_url_kwarg
  104. self.remove_url_name_components = remove_url_name_components
  105. def render(self, record, value, bound_column):
  106. table = bound_column._table
  107. if self.kwargs_callable is not None:
  108. kwargs = self.kwargs_callable(table.view, record, value)
  109. elif self.pk_url_kwarg is not None:
  110. kwargs = {self.pk_url_kwarg: record.pk}
  111. else:
  112. kwargs = None
  113. return self.render_link(
  114. table.viewset.get_relative_view_url(self.url_name_suffix, remove_url_name_components=self.remove_url_name_components, kwargs=kwargs, query_params=table.GET),
  115. record=record,
  116. value=value
  117. )
  118. @library.register
  119. class DateColumnEx(DateTimeColumnBase):
  120. SHORT_FORMAT = 'SHORT_DATE_FORMAT'
  121. LONG_FORMAT = 'DATE_FORMAT'
  122. def render(self, record, value, bound_column):
  123. if value is None:
  124. return bound_column.default
  125. return date_format(self.convert_value(record, value, bound_column), self.format)
  126. @library.register
  127. class DateTimeColumnEx(DateColumnEx):
  128. SHORT_FORMAT = 'SHORT_DATETIME_FORMAT'
  129. LONG_FORMAT = 'DATETIME_FORMAT'
  130. @library.register
  131. class TimeColumnEx(DateTimeColumnBase):
  132. SHORT_FORMAT = None
  133. LONG_FORMAT = 'TIME_FORMAT'
  134. def render(self, record, value, bound_column):
  135. if value is None:
  136. return bound_column.default
  137. return time_format(self.convert_value(record, value, bound_column), self.format)