Django-filter: ๋ฒ”์œ„ ํ•„ํ„ฐ์˜ ์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜์— ๋Œ€ํ•œ URL์˜ ์‚ฌ์šฉ์ž ์ •์˜ ์ด๋ฆ„?

์— ๋งŒ๋“  2015๋…„ 09์›” 20์ผ  ยท  3์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: carltongibson/django-filter

์ฟผ๋ฆฌ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ URL์— ์‚ฌ์šฉ๋œ ํ•„๋“œ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.
ํ˜„์žฌ

class TransactionFilter(django_filters.FilterSet):
    created = django_filters.DateFromToRangeFilter()
    class Meta:
        model = models.Transaction
        fields = ('created', )

์š”์ฒญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

/api/transaction?created_0=2015-01-01&created_1=2015-01-02

์ด๊ฒƒ์€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€๋งŒ ๋งค์šฐ ์ง๊ด€์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฒ”์œ„ ํ•„๋“œ์— ๋‹ค๋ฅธ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

/api/transaction?created_since=2015-01-01&created_until=2015-01-02

๊ณ ๋งˆ์›Œ, ํ•˜ํ‚ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋‹ค์Œ์€ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด MultiWidget ๋ฅผ ์„œ๋ธŒํด๋ž˜์‹ฑํ•˜๋Š” ์˜ˆ์ž…๋‹ˆ๋‹ค. start ๋ฐ end ๋ฅผ ํ•„๋“œ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

from django.utils.safestring import mark_safe

from django_filters.fields import DateRangeField
from django_filters.filters import RangeFilter
from django_filters.widgets import RangeWidget


class StartEndRangeWidget(RangeWidget):
    """
    A range widget that uses 'start' and 'end' instead of '0' and '1'.
    """

    attr_names = ('start', 'end')

    def render(self, name, value, attrs=None):
        if self.is_localized:
            for widget in self.widgets:
                widget.is_localized = self.is_localized

        # value is a list of values, each corresponding to a widget
        # in self.widgets.
        if not isinstance(value, list):
            value = self.decompress(value)

        output = []
        final_attrs = self.build_attrs(attrs)
        id_ = final_attrs.get('id')

        for i, widget in enumerate(self.widgets):
            try:
                widget_value = value[i]
            except IndexError:
                widget_value = None

            if id_:
                final_attrs = dict(final_attrs,
                                   id='%s_%s' % (id_, self.attr_names[i]))

            output.append(widget.render(name + '_%s' % self.attr_names[i],
                                        widget_value, final_attrs))

        return mark_safe(self.format_output(output))

    def value_from_datadict(self, data, files, name):
        return [widget.value_from_datadict(data, files,
                                           name + '_%s' % self.attr_names[i])
                for i, widget in enumerate(self.widgets)]


class StartEndDateRangeField(DateRangeField):
    """
    A DateRangeField that uses 'start' and 'end'.
    """

    widget = StartEndRangeWidget


class StartEndDateFromToRangeFilter(RangeFilter):
    """
    A RangeFilter that uses 'start' and 'end'.
    """

    field_class = StartEndDateRangeField

๋ชจ๋“  3 ๋Œ“๊ธ€

ํ . ์ œ ์ƒ๊ฐ์— ์—ฌ๊ธฐ์— ๋‹ต์€ _์‚ฌ์‹ค์ด ์•„๋‹™๋‹ˆ๋‹ค_ โ€” ์†์„ ๋”๋Ÿฝํžˆ๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋ฉด...

_0, _1 ๋ถ€์†๋ฌผ์— ๋Œ€ํ•œ ๋…ผ๋ฆฌ๋Š” django.forms.widgets.MultiWidget.render ์—์„œ ์™”์Šต๋‹ˆ๋‹ค. ( RangeFilter ๋Š” $ MultiWidget ํ•˜์œ„ ํด๋ž˜์Šค์ธ RangeWidget ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” RangeField ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.)

์›ํ•˜๋Š” ์ด๋ฆ„์„ ์–ป์œผ๋ ค๋ฉด render ๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ผ์น˜ํ•˜๋Š” value_from_datadict ๋„ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•ด MultiWidget ๋ฅผ ์„œ๋ธŒํด๋ž˜์‹ฑํ•˜๋Š” ์˜ˆ์ž…๋‹ˆ๋‹ค. start ๋ฐ end ๋ฅผ ํ•„๋“œ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

from django.utils.safestring import mark_safe

from django_filters.fields import DateRangeField
from django_filters.filters import RangeFilter
from django_filters.widgets import RangeWidget


class StartEndRangeWidget(RangeWidget):
    """
    A range widget that uses 'start' and 'end' instead of '0' and '1'.
    """

    attr_names = ('start', 'end')

    def render(self, name, value, attrs=None):
        if self.is_localized:
            for widget in self.widgets:
                widget.is_localized = self.is_localized

        # value is a list of values, each corresponding to a widget
        # in self.widgets.
        if not isinstance(value, list):
            value = self.decompress(value)

        output = []
        final_attrs = self.build_attrs(attrs)
        id_ = final_attrs.get('id')

        for i, widget in enumerate(self.widgets):
            try:
                widget_value = value[i]
            except IndexError:
                widget_value = None

            if id_:
                final_attrs = dict(final_attrs,
                                   id='%s_%s' % (id_, self.attr_names[i]))

            output.append(widget.render(name + '_%s' % self.attr_names[i],
                                        widget_value, final_attrs))

        return mark_safe(self.format_output(output))

    def value_from_datadict(self, data, files, name):
        return [widget.value_from_datadict(data, files,
                                           name + '_%s' % self.attr_names[i])
                for i, widget in enumerate(self.widgets)]


class StartEndDateRangeField(DateRangeField):
    """
    A DateRangeField that uses 'start' and 'end'.
    """

    widget = StartEndRangeWidget


class StartEndDateFromToRangeFilter(RangeFilter):
    """
    A RangeFilter that uses 'start' and 'end'.
    """

    field_class = StartEndDateRangeField

@beaugunderson , ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” (๋‚ด ๊ฒฝ์šฐ์™€ ๊ฐ™์ด) lt / gt ์™€ ํ•จ๊ป˜ ๋‘ ๊ฐœ์˜ ๋‚ ์งœ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ์‰ฝ๋‹ค๋Š” ์ ์„ ์–ธ๊ธ‰ํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰