Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using DateRangePicker in filters #58

Open
davecoates opened this issue Oct 28, 2024 · 1 comment
Open

Using DateRangePicker in filters #58

davecoates opened this issue Oct 28, 2024 · 1 comment

Comments

@davecoates
Copy link
Contributor

The default widget in django_filters for date ranges is just a plain text input. We should provide a filter to use the DateRangePicker.

Here's one possibility, but requires explicitly defining it. As far as I know this is the only option - it doesn't look like you can override a template for the default range filters specifically for dates, only the generic multiwidget.html

from django.utils import timezone
from django.utils.dateparse import parse_datetime
from django_filters.widgets import DateRangeWidget


class DateRangePickerWidget(DateRangeWidget):
    """Use @alliancesoftware/ui DateRangePicker as a django filters widget

    Usage::

        # On a FilterSet
        field_name = filters.IsoDateTimeFromToRangeFilter(widget=DateRangePickerWidget())

        # You can specify granularity
        field_name = filters.IsoDateTimeFromToRangeFilter(widget=DateRangePickerWidget(granularity="day))

        # By default timezone will be hidden, and will be set to the local timezone as returned by timezone.localtime()
        # You can display the timezone by setting hide_time_zone=False
        field_name = filters.IsoDateTimeFromToRangeFilter(widget=DateRangePickerWidget(hide_time_zone=False))
        # To use a different timezone you can pass a value to ``placeholder_value``, e.g. UTC:
        field_name = filters.IsoDateTimeFromToRangeFilter(widget=DateRangePickerWidget(hide_time_zone=False, placeholder_value=timezone.now()))
    """

    template_name = "django/forms/widgets/datetime_range_widget.html"

    #: Whether to explicitly show the timezone in the widget. Defaults to ``False``.
    hide_time_zone: bool
    #: The granularity of the widget. One of "hour" "minute" "second" "day"
    granularity: str | None
    #: Used by the widget to determine timezone when no value is passed. Defaults to ``timezone.localtime()``.
    placeholder_value: timezone.datetime

    def __init__(self, *args, hide_time_zone=True, granularity=None, placeholder_value=None, **kwargs):
        super().__init__(*args, **kwargs)
        self.hide_time_zone = hide_time_zone
        self.granularity = granularity
        if placeholder_value is None:
            placeholder_value = timezone.localtime()
        self.placeholder_value = placeholder_value

    def get_context(self, name, value, attrs):
        # This is used to determine the default timezone
        attrs["placeholder_value"] = self.placeholder_value
        attrs["hide_time_zone"] = self.hide_time_zone
        attrs["granularity"] = self.granularity
        context = super().get_context(name, value, attrs)
        if value and all(value):
            context["range_value"] = {
                "start": timezone.localtime(parse_datetime(value[0])),
                "end": timezone.localtime(parse_datetime(value[1])),
            }
        return context

    def value_from_datadict(self, data, files, name):
        # Frontend submits values like'2024-08-12T09:40:16+10:00[Australia/Melbourne] - remove the timezone in square braces
        value = super().value_from_datadict(data, files, name)
        return [v.split("[")[0] if v else v for v in value]

Template

{% load react %}

{% component "@alliancesoftware/ui" "DateRangePicker" props=widget.attrs|merge_props:extra_widget_props|html_attr_to_jsx default_value=range_value start_name=widget.name|add:"_after" end_name=widget.name|add:"_before" %}
{% endcomponent %}

(we can provide a specific tag like we do for DatePicker, ^ this just an example that I've tested)

@davecoates
Copy link
Contributor Author

Some things to consider with the above

  • handling a date instead of datetime, currently will cause some problems on re-submit after value prefilled
  • passing granularity of None through to the widget appears to behave differently than not passing it at all
  • maybe different versions for date vs datetime?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant