PageRenderTime 30ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/litclub/django/contrib/admin/templatetags/admin_modify.py

https://github.com/andrewkuzmych/litclub
Python | 253 lines | 242 code | 5 blank | 6 comment | 2 complexity | 98abe0acd3b8fb918953f148b2cd242f MD5 | raw file
  1. from django import template
  2. from django.contrib.admin.views.main import AdminBoundField
  3. from django.template import loader
  4. from django.utils.text import capfirst
  5. from django.utils.encoding import force_unicode
  6. from django.utils.safestring import mark_safe
  7. from django.utils.html import escape
  8. from django.db import models
  9. from django.db.models.fields import Field
  10. from django.db.models.related import BoundRelatedObject
  11. from django.conf import settings
  12. import re
  13. register = template.Library()
  14. word_re = re.compile('[A-Z][a-z]+')
  15. absolute_url_re = re.compile(r'^(?:http(?:s)?:/)?/', re.IGNORECASE)
  16. def class_name_to_underscored(name):
  17. return u'_'.join([s.lower() for s in word_re.findall(name)[:-1]])
  18. def include_admin_script(script_path):
  19. """
  20. Returns an HTML script element for including a script from the admin
  21. media url (or other location if an absolute url is given).
  22. Example usage::
  23. {% include_admin_script "js/calendar.js" %}
  24. could return::
  25. <script type="text/javascript" src="/media/admin/js/calendar.js">
  26. """
  27. if not absolute_url_re.match(script_path):
  28. script_path = '%s%s' % (settings.ADMIN_MEDIA_PREFIX, script_path)
  29. return mark_safe(u'<script type="text/javascript" src="%s"></script>'
  30. % script_path)
  31. include_admin_script = register.simple_tag(include_admin_script)
  32. def submit_row(context):
  33. opts = context['opts']
  34. change = context['change']
  35. is_popup = context['is_popup']
  36. return {
  37. 'onclick_attrib': (opts.get_ordered_objects() and change
  38. and 'onclick="submitOrderForm();"' or ''),
  39. 'show_delete_link': (not is_popup and context['has_delete_permission']
  40. and (change or context['show_delete'])),
  41. 'show_save_as_new': not is_popup and change and opts.admin.save_as,
  42. 'show_save_and_add_another': not is_popup and (not opts.admin.save_as or context['add']),
  43. 'show_save_and_continue': not is_popup and context['has_change_permission'],
  44. 'show_save': True
  45. }
  46. submit_row = register.inclusion_tag('admin/submit_line.html', takes_context=True)(submit_row)
  47. def field_label(bound_field):
  48. class_names = []
  49. if isinstance(bound_field.field, models.BooleanField):
  50. class_names.append("vCheckboxLabel")
  51. colon = ""
  52. else:
  53. if not bound_field.field.blank:
  54. class_names.append('required')
  55. if not bound_field.first:
  56. class_names.append('inline')
  57. colon = ":"
  58. class_str = class_names and u' class="%s"' % u' '.join(class_names) or u''
  59. return mark_safe(u'<label for="%s"%s>%s%s</label> ' %
  60. (bound_field.element_id, class_str,
  61. escape(force_unicode(capfirst(bound_field.field.verbose_name))),
  62. colon))
  63. field_label = register.simple_tag(field_label)
  64. class FieldWidgetNode(template.Node):
  65. nodelists = {}
  66. default = None
  67. def __init__(self, bound_field_var):
  68. self.bound_field_var = template.Variable(bound_field_var)
  69. def get_nodelist(cls, klass):
  70. if klass not in cls.nodelists:
  71. try:
  72. field_class_name = klass.__name__
  73. template_name = u"widget/%s.html" % class_name_to_underscored(field_class_name)
  74. nodelist = loader.get_template(template_name).nodelist
  75. except template.TemplateDoesNotExist:
  76. super_klass = bool(klass.__bases__) and klass.__bases__[0] or None
  77. if super_klass and super_klass != Field:
  78. nodelist = cls.get_nodelist(super_klass)
  79. else:
  80. if not cls.default:
  81. cls.default = loader.get_template("widget/default.html").nodelist
  82. nodelist = cls.default
  83. cls.nodelists[klass] = nodelist
  84. return nodelist
  85. else:
  86. return cls.nodelists[klass]
  87. get_nodelist = classmethod(get_nodelist)
  88. def render(self, context):
  89. bound_field = self.bound_field_var.resolve(context)
  90. context.push()
  91. context['bound_field'] = bound_field
  92. output = self.get_nodelist(bound_field.field.__class__).render(context)
  93. context.pop()
  94. return output
  95. class FieldWrapper(object):
  96. def __init__(self, field ):
  97. self.field = field
  98. def needs_header(self):
  99. return not isinstance(self.field, models.AutoField)
  100. def header_class_attribute(self):
  101. return self.field.blank and mark_safe(' class="optional"') or ''
  102. def use_raw_id_admin(self):
  103. return isinstance(self.field.rel, (models.ManyToOneRel, models.ManyToManyRel)) \
  104. and self.field.rel.raw_id_admin
  105. class FormFieldCollectionWrapper(object):
  106. def __init__(self, field_mapping, fields, index):
  107. self.field_mapping = field_mapping
  108. self.fields = fields
  109. self.bound_fields = [AdminBoundField(field, self.field_mapping, field_mapping['original'])
  110. for field in self.fields]
  111. self.index = index
  112. class TabularBoundRelatedObject(BoundRelatedObject):
  113. def __init__(self, related_object, field_mapping, original):
  114. super(TabularBoundRelatedObject, self).__init__(related_object, field_mapping, original)
  115. self.field_wrapper_list = [FieldWrapper(field) for field in self.relation.editable_fields()]
  116. fields = self.relation.editable_fields()
  117. self.form_field_collection_wrappers = [FormFieldCollectionWrapper(field_mapping, fields, i)
  118. for (i,field_mapping) in self.field_mappings.items() ]
  119. self.original_row_needed = max([fw.use_raw_id_admin() for fw in self.field_wrapper_list])
  120. self.show_url = original and hasattr(self.relation.opts, 'get_absolute_url')
  121. def template_name(self):
  122. return "admin/edit_inline_tabular.html"
  123. class StackedBoundRelatedObject(BoundRelatedObject):
  124. def __init__(self, related_object, field_mapping, original):
  125. super(StackedBoundRelatedObject, self).__init__(related_object, field_mapping, original)
  126. fields = self.relation.editable_fields()
  127. self.field_mappings.fill()
  128. self.form_field_collection_wrappers = [FormFieldCollectionWrapper(field_mapping ,fields, i)
  129. for (i,field_mapping) in self.field_mappings.items()]
  130. self.show_url = original and hasattr(self.relation.opts, 'get_absolute_url')
  131. def template_name(self):
  132. return "admin/edit_inline_stacked.html"
  133. class EditInlineNode(template.Node):
  134. def __init__(self, rel_var):
  135. self.rel_var = template.Variable(rel_var)
  136. def render(self, context):
  137. relation = self.rel_var.resolve(context)
  138. context.push()
  139. if relation.field.rel.edit_inline == models.TABULAR:
  140. bound_related_object_class = TabularBoundRelatedObject
  141. elif relation.field.rel.edit_inline == models.STACKED:
  142. bound_related_object_class = StackedBoundRelatedObject
  143. else:
  144. bound_related_object_class = relation.field.rel.edit_inline
  145. original = context.get('original', None)
  146. bound_related_object = relation.bind(context['form'], original, bound_related_object_class)
  147. context['bound_related_object'] = bound_related_object
  148. t = loader.get_template(bound_related_object.template_name())
  149. output = t.render(context)
  150. context.pop()
  151. return output
  152. def output_all(form_fields):
  153. return u''.join([force_unicode(f) for f in form_fields])
  154. output_all = register.simple_tag(output_all)
  155. def auto_populated_field_script(auto_pop_fields, change = False):
  156. t = []
  157. for field in auto_pop_fields:
  158. if change:
  159. t.append(u'document.getElementById("id_%s")._changed = true;' % field.name)
  160. else:
  161. t.append(u'document.getElementById("id_%s").onchange = function() { this._changed = true; };' % field.name)
  162. add_values = u' + " " + '.join([u'document.getElementById("id_%s").value' % g for g in field.prepopulate_from])
  163. for f in field.prepopulate_from:
  164. t.append(u'document.getElementById("id_%s").onkeyup = function() {' \
  165. ' var e = document.getElementById("id_%s");' \
  166. ' if(!e._changed) { e.value = URLify(%s, %s);} }; ' % (
  167. f, field.name, add_values, field.max_length))
  168. return mark_safe(u''.join(t))
  169. auto_populated_field_script = register.simple_tag(auto_populated_field_script)
  170. def filter_interface_script_maybe(bound_field):
  171. f = bound_field.field
  172. if f.rel and isinstance(f.rel, models.ManyToManyRel) and f.rel.filter_interface:
  173. return mark_safe(u'<script type="text/javascript">addEvent(window, "load", function(e) {' \
  174. ' SelectFilter.init("id_%s", "%s", %s, "%s"); });</script>\n' % (
  175. f.name, escape(f.verbose_name.replace('"', '\\"')), f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX))
  176. else:
  177. return ''
  178. filter_interface_script_maybe = register.simple_tag(filter_interface_script_maybe)
  179. def field_widget(parser, token):
  180. bits = token.contents.split()
  181. if len(bits) != 2:
  182. raise template.TemplateSyntaxError, "%s takes 1 argument" % bits[0]
  183. return FieldWidgetNode(bits[1])
  184. field_widget = register.tag(field_widget)
  185. def edit_inline(parser, token):
  186. bits = token.contents.split()
  187. if len(bits) != 2:
  188. raise template.TemplateSyntaxError, "%s takes 1 argument" % bits[0]
  189. return EditInlineNode(bits[1])
  190. edit_inline = register.tag(edit_inline)
  191. def admin_field_line(context, argument_val):
  192. if isinstance(argument_val, AdminBoundField):
  193. bound_fields = [argument_val]
  194. else:
  195. bound_fields = [bf for bf in argument_val]
  196. add = context['add']
  197. change = context['change']
  198. class_names = ['form-row']
  199. for bound_field in bound_fields:
  200. for f in bound_field.form_fields:
  201. if f.errors():
  202. class_names.append('errors')
  203. break
  204. # Assumes BooleanFields won't be stacked next to each other!
  205. if isinstance(bound_fields[0].field, models.BooleanField):
  206. class_names.append('checkbox-row')
  207. return {
  208. 'add': context['add'],
  209. 'change': context['change'],
  210. 'bound_fields': bound_fields,
  211. 'class_names': " ".join(class_names),
  212. }
  213. admin_field_line = register.inclusion_tag('admin/field_line.html', takes_context=True)(admin_field_line)