Source code for pytoolbox.django.forms.utils

"""
Some utilities related to the forms.
"""

from copy import copy

from django.contrib import messages
from django.forms.utils import ErrorList

from pytoolbox import module

_all = module.All(globals())


[docs]def conditional_required(form, required_dict, data=None, cleanup=False): """ Toggle requirement of some fields based on a dictionary with 'field name' -> 'required boolean'. """ data = data or form.cleaned_data for name, value in data.items(): required = required_dict.get(name, None) if required and not value: form._errors[name] = ErrorList(['This field is required.']) if required is False and cleanup: data[name] = None return data
[docs]def get_instance(form, field_name, request, msg=None): """ Return the instance if the `form` is valid, or try to get it from database. Return None if not found and add an error message if set. """ if form.is_valid(): return form.cleaned_data[field_name] queryset = form.fields[field_name].queryset try: return queryset.get(pk=form.data[form.add_prefix(field_name)]) except (KeyError, queryset.model.DoesNotExist): if msg: messages.error(request, msg)
[docs]def set_disabled(form, field_name, value=False): """Toggle the disabled attribute of a form's field.""" if value: form.fields[field_name].widget.attrs['disabled'] = True else: try: del form.fields[field_name].widget.attrs['disabled'] except Exception: pass
[docs]def update_widget_attributes(widget, updates): """ Update attributes of a `widget` with content of `updates` handling classes addition [+], removal [-] and toggle [^]. **Example usage** >>> from pytoolbox.unittest import asserts >>> widget = type(str(''), (), {}) >>> widget.attrs = {'class': 'mondiale'} >>> update_widget_attributes( ... widget, {'class': '+pigeon +pigeon +voyage -mondiale -mondiale, ^voyage ^voyageur'}) >>> asserts.dict_equal(widget.attrs, {'class': 'pigeon voyageur'}) >>> update_widget_attributes(widget, {'class': '+le', 'cols': 100}) >>> asserts.dict_equal(widget.attrs, {'class': 'le pigeon voyageur', 'cols': 100}) """ updates = copy(updates) if 'class' in updates: class_set = set([c for c in widget.attrs.get('class', '').split(' ') if c]) for cls in set([c for c in updates['class'].split(' ') if c]): operation, cls = cls[0], cls[1:] if operation == '+' or (operation == '^' and cls not in class_set): class_set.add(cls) elif operation in ('-', '^'): class_set.discard(cls) else: raise ValueError( 'updates must be a valid string with "<op>class <op>..." with op in [+-^].') widget.attrs['class'] = ' '.join(sorted(class_set)) del updates['class'] widget.attrs.update(updates)
[docs]def validate_start_end(form, data=None, start_name='start_date', end_name='end_date'): """ Check that the field containing the value of the start field (time, ...) is not bigger (>) than the stop. """ data = data or form.cleaned_data start, end = data[start_name], data[end_name] if start and end and start > end: form._errors[end_name] = ErrorList([ f"The {start_name.replace('_', ' ')} cannot be before the {end_name.replace('_', ' ')}." ])
__all__ = _all.diff(globals())