/renderform/templatetags/forms.py

https://bitbucket.org/baratrion/django-renderform · Python · 114 lines · 96 code · 11 blank · 7 comment · 20 complexity · 0039bfd8da2aae181461755d8e409211 MD5 · raw file

  1. from django.template import Library, Node
  2. from django import forms
  3. import re
  4. register = Library()
  5. SPLIT_RE = re.compile(r'[\s,]+')
  6. def show_form(form, wrap_with_tag='div'):
  7. "Render all fields in `form`, passing `wrap_with_tag` to `show_field`."
  8. return {'form': form, 'tag': wrap_with_tag}
  9. register.inclusion_tag("forms/form.html")(show_form)
  10. def show_field(field, wrap_with_tag='div', classes=()):
  11. "Render `field` (label, input, and help text) encosed in `wrap_with_tag`."
  12. if isinstance(classes, basestring):
  13. classes = classes.split(',')
  14. is_checkbox = (
  15. isinstance(field.field.widget, forms.widgets.CheckboxInput) or
  16. getattr(field.field.widget, 'input_type', None) == 'checkbox'
  17. )
  18. is_radio = (
  19. isinstance(field.field.widget, forms.widgets.RadioInput) or
  20. getattr(field.field.widget, 'input_type', None) == 'radio'
  21. )
  22. return {
  23. 'field': field,
  24. 'errors': field.errors,
  25. 'is_hidden': field.is_hidden,
  26. 'is_checkbox': is_checkbox,
  27. 'is_radio': is_radio,
  28. 'tag': wrap_with_tag,
  29. 'classes': classes,
  30. 'required': field.field.required
  31. }
  32. register.inclusion_tag("forms/field.html")(show_field)
  33. def show_errors(field_or_errors, errors=None):
  34. if errors is None:
  35. if isinstance(field_or_errors, forms.forms.BoundField):
  36. field = field_or_errors
  37. errors = field.errors.pop()
  38. else:
  39. field = None
  40. errors = field_or_errors
  41. else:
  42. field = field_or_errors
  43. return {'field': field, 'errors': errors}
  44. register.inclusion_tag("forms/errors.html")(show_errors)
  45. def show_label(field, label=None, classes=()):
  46. "Render the label tag for `field`, overriding its label text with `label`."
  47. if label is None:
  48. label = field.label
  49. if isinstance(classes, basestring):
  50. classes = SPLIT_RE.split(classes)
  51. return {
  52. 'field': field,
  53. 'label': label,
  54. 'classes': classes,
  55. 'required': field.field.required
  56. }
  57. register.inclusion_tag("forms/label.html")(show_label)
  58. def show_help_text(field_or_text, classes=()):
  59. "Render the text or the field's help text given by `field_or_text`."
  60. if isinstance(field_or_text, basestring):
  61. field = None
  62. help_text = field_or_text
  63. else:
  64. field = field_or_text
  65. help_text = field.help_text
  66. if isinstance(classes, basestring):
  67. classes = SPLIT_RE.split(classes)
  68. return {'field': field, 'help_text': help_text, 'classes': classes}
  69. register.inclusion_tag("forms/help_text.html")(show_help_text)
  70. def do_class_list(parser, token):
  71. "Resolve arguments, flatten lists, and split strings to get class names."
  72. bits = token.split_contents()[1:]
  73. class_vars = [parser.compile_filter(bit) for bit in bits]
  74. return ClassListNode(class_vars)
  75. register.tag('class_list', do_class_list)
  76. def do_class_attr(parser, token):
  77. """
  78. Render a HTML class attribute if the given classes are non-empty,
  79. otherwise returns an empty string to avoid including an empty attribute.
  80. Takes the same arguments as `class_list`. The attribute name is prefixed
  81. with a space to help avoid extraneous spaces.
  82. """
  83. bits = token.split_contents()[1:]
  84. class_vars = [parser.compile_filter(bit) for bit in bits]
  85. return ClassListNode(class_vars, ' class="%s"')
  86. register.tag('class_attr', do_class_attr)
  87. class ClassListNode(Node):
  88. def __init__(self, class_vars, output_format="%s"):
  89. self.class_vars = class_vars
  90. self.output_format = output_format
  91. def render(self, context):
  92. classes = [var.resolve(context) for var in self.class_vars]
  93. class_names = []
  94. for class_ in classes:
  95. if isinstance(class_, basestring):
  96. class_ = [class_]
  97. for names in class_:
  98. for name in SPLIT_RE.split(names):
  99. if name and name not in class_names:
  100. class_names.append(name)
  101. value = " ".join(class_names)
  102. return value and self.output_format % value