Skip to content

Instantly share code, notes, and snippets.

@pipermerriam
Created February 6, 2013 15:54
Show Gist options
  • Save pipermerriam/4723485 to your computer and use it in GitHub Desktop.
Save pipermerriam/4723485 to your computer and use it in GitHub Desktop.
Various django objects and helpers.
class ClearableFileInput(widgets.ClearableFileInput):
"""
Changes the default file widget to be easier to target with CSS
"""
template_with_initial = u'<div class="fileField"><span class="currently">%(initial_text)s:</span> %(initial)s %(clear_template)s<span class="change">%(input_text)s:</span> %(input)s</div>'
template_with_clear = u'<div class="clear">%(clear)s <label for="%(clear_checkbox_id)s">%(clear_checkbox_label)s</label></div>'
initial_template = u'<a href="{{url}}">{{name}}</a>'
def render(self, name, value, attrs=None):
substitutions = {
'initial_text': self.initial_text,
'input_text': self.input_text,
'clear_template': '',
'clear_checkbox_label': self.clear_checkbox_label,
}
template = u'%(input)s'
substitutions['input'] = widgets.FileInput.render(self, name, value, attrs)
if value and hasattr(value, "url"):
template = self.template_with_initial
substitutions['initial'] = Template(self.initial_template).render(Context({
'url': escape(value.url),
'name': escape(force_unicode(value)),
'value': value,
}))
if not self.is_required:
checkbox_name = self.clear_checkbox_name(name)
checkbox_id = self.clear_checkbox_id(checkbox_name)
substitutions['clear_checkbox_name'] = conditional_escape(checkbox_name)
substitutions['clear_checkbox_id'] = conditional_escape(checkbox_id)
substitutions['clear'] = widgets.CheckboxInput().render(checkbox_name, False, attrs={'id': checkbox_id})
substitutions['clear_template'] = self.template_with_clear % substitutions
return mark_safe(template % substitutions)
class ImageInput(ClearableFileInput):
template_with_initial = u'<div class="fileField">%(initial)s %(clear_template)s<span class="change">%(input_text)s:</span> %(input)s</div>'
initial_template = u'{% load thumbnail %}{% thumbnail value.path "100x100" as img %}<img src="{% media img.name %}">{% endthumbnail %}'
clear_checkbox_label = 'Delete Image'
class CSSClassMixin(object):
error_css_class = 'error'
required_css_class = 'required'
class NonBraindamagedErrorMixin(object):
def field_error(self, name, error):
self._errors = self._errors or ErrorDict()
self._errors.setdefault(name, ErrorList())
self._errors[name].append(error)
class SortedIterableDict(SortedDict):
"""
Used as a template object that allows for dictionary style lookups, yet
iterates over the values.
"""
def __iter__(self):
for key in super(SortedIterableDict, self).__iter__():
yield self[key]
class FieldsetMixin(NonBraindamagedErrorMixin):
FIELDSETS = tuple()
def get_fieldsets(self):
return self.FIELDSETS
def fieldset_error(self, name, error):
fieldset = self.fieldsets[name]
fieldset.errors = getattr(fieldset, 'errors', ErrorList())
fieldset.errors.append(error)
self.field_error(name, error)
@cached_property
def fieldsets(self):
fieldsets = SortedIterableDict()
for fieldset_name, fieldset in self.get_fieldsets():
fieldsets[fieldset_name] = SortedDict({
'name': fieldset_name,
'fields': SortedIterableDict([(field, self[field]) for field in fieldset.get('fields', [])]),
'css_classes': ' '.join(fieldset.get('css_classes', [])),
'template_name': fieldset.get('template_name'),
}.items())
return fieldsets
class BaseForm(FieldsetMixin, CSSClassMixin, forms.Form):
pass
class BaseModelForm(FieldsetMixin, CSSClassMixin, forms.ModelForm):
pass
class USPhoneNumberFieldExtension(forms.CharField):
regex = re.compile(r"""
^(?P<phone>
(\d+[ .-]?)? # country code
\(?\d{3}\)?[ .-]? # area code
\d{3}[ .-]? # first 3
\d{4}[ .-]? # first 4
)
# extension
(\s*(e|x|ext|ex|extension|xt)\.?\s*(?P<ext>\S+))?
$""", re.X)
def clean(self, value):
super(USPhoneNumberFieldExtension, self).clean(value)
if value in EMPTY_VALUES:
return ''
matches = self.regex.match(value)
if not matches:
raise forms.ValidationError('Phone numbers must be in [X-]XXX-XXX-XXXX[ex. XXX] format')
phone = strip_nondigits(matches.group('phone'))
ext = strip_nondigits(matches.group('ext') or '')
groups = re.match('(\d*)(\d{3})(\d{3})(\d{4})$', phone).groups()
groups = filter(bool, groups)
phone = '-'.join(groups)
if ext:
phone += ' ex. ' + ext
return phone
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment