Source code for django.contrib.postgres.forms.ranges

from django import forms
from django.core import exceptions
from django.db.backends.postgresql.psycopg_any import (
    DateRange,
    DateTimeTZRange,
    NumericRange,
)
from django.forms.widgets import HiddenInput, MultiWidget
from django.utils.translation import gettext_lazy as _

__all__ = [
    "BaseRangeField",
    "IntegerRangeField",
    "DecimalRangeField",
    "DateTimeRangeField",
    "DateRangeField",
    "HiddenRangeWidget",
    "RangeWidget",
]


[docs]class RangeWidget(MultiWidget): def __init__(self, base_widget, attrs=None): widgets = (base_widget, base_widget) super().__init__(widgets, attrs)
[docs] def decompress(self, value): if value: return (value.lower, value.upper) return (None, None)
class HiddenRangeWidget(RangeWidget): """A widget that splits input into two <input type="hidden"> inputs.""" def __init__(self, attrs=None): super().__init__(HiddenInput, attrs) class BaseRangeField(forms.MultiValueField): default_error_messages = { "invalid": _("Enter two valid values."), "bound_ordering": _( "The start of the range must not exceed the end of the range." ), } hidden_widget = HiddenRangeWidget def __init__(self, **kwargs): if "widget" not in kwargs: kwargs["widget"] = RangeWidget(self.base_field.widget) if "fields" not in kwargs: kwargs["fields"] = [ self.base_field(required=False), self.base_field(required=False), ] kwargs.setdefault("required", False) kwargs.setdefault("require_all_fields", False) self.range_kwargs = {} if default_bounds := kwargs.pop("default_bounds", None): self.range_kwargs = {"bounds": default_bounds} super().__init__(**kwargs) def prepare_value(self, value): lower_base, upper_base = self.fields if isinstance(value, self.range_type): return [ lower_base.prepare_value(value.lower), upper_base.prepare_value(value.upper), ] if value is None: return [ lower_base.prepare_value(None), upper_base.prepare_value(None), ] return value def compress(self, values): if not values: return None lower, upper = values if lower is not None and upper is not None and lower > upper: raise exceptions.ValidationError( self.error_messages["bound_ordering"], code="bound_ordering", ) try: range_value = self.range_type(lower, upper, **self.range_kwargs) except TypeError: raise exceptions.ValidationError( self.error_messages["invalid"], code="invalid", ) else: return range_value
[docs]class IntegerRangeField(BaseRangeField): default_error_messages = {"invalid": _("Enter two whole numbers.")} base_field = forms.IntegerField range_type = NumericRange
[docs]class DecimalRangeField(BaseRangeField): default_error_messages = {"invalid": _("Enter two numbers.")} base_field = forms.DecimalField range_type = NumericRange
[docs]class DateTimeRangeField(BaseRangeField): default_error_messages = {"invalid": _("Enter two valid date/times.")} base_field = forms.DateTimeField range_type = DateTimeTZRange
[docs]class DateRangeField(BaseRangeField): default_error_messages = {"invalid": _("Enter two valid dates.")} base_field = forms.DateField range_type = DateRange
Back to Top