Django-filter: Django-Taggit ํ•„ํ„ฐ(์š”์ฒญ)

์— ๋งŒ๋“  2016๋…„ 08์›” 16์ผ  ยท  11์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: carltongibson/django-filter

๋ณ„์ ์œผ๋กœ ๋ณด๋ฉด django-taggit ์€ django-filter๋งŒํผ ์ธ๊ธฐ๊ฐ€ ์žˆ์œผ๋ฉฐ Django์—์„œ ํƒœ๊ทธ๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•œ ์ตœ๊ณ ์˜ ์†”๋ฃจ์…˜์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. 2010๋…„๋ถ€ํ„ฐ ์‚ฌ์šฉ๋˜์—ˆ์œผ๋ฉฐ ์ •๊ธฐ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜๋ฉฐ ์—ฌ๋Ÿฌ ๋ช…์˜ ์ •๊ธฐ ๊ธฐ๊ณ ์ž๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

django-taggit ํ•„ํ„ฐ์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•˜์„ธ์š”?

๋‚ด๊ฐ€ ์ด๊ฒƒ์— ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

tags = django_filters.ModelMultipleChoiceFilter(
        name='tags__name',
        to_field_name='name',
        conjoined=True,
        distinct=True,
        queryset=Tag.objects.all(),
    )

ํ•˜์ง€๋งŒ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค('TeSt' ํƒœ๊ทธ์— ๋Œ€ํ•œ ํ•„ํ„ฐ๋Š” 'test' ํƒœ๊ทธ๊ฐ€ ์žˆ๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•จ).

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

์ตœ์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ ์ž‘์—… ์˜ˆ:

from taggit.forms import TagField
from django_filters.views import FilterView

class TagFilter(django_filters.CharFilter):
    field_class = TagField

    def __init__(self, *args, **kwargs):
        kwargs.setdefault('lookup_expr', 'in')
        super().__init__(*args, **kwargs)


class MyFilter(django_filters.FilterSet):
    tags = TagFilter(field_name='tags__name')

    class Meta:
        model = MyModel

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

TaggitFilter ์€ ์ผ๋ฐ˜ ModelMultipleChoiceFilter ์–ด๋–ป๊ฒŒ ๋‹ค๋ฆ…๋‹ˆ๊นŒ?

๋˜ํ•œ ๋‹จ์ˆœํžˆ ์กฐํšŒ์™€ ํ•„๋“œ ์ด๋ฆ„์„ ๊ฒฐํ•ฉํ•˜์—ฌ ์—ฌ๊ธฐ ์— lookup_expr ์ง€์›์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ™•์‹ ํ•ฉ๋‹ˆ๋‹ค.

ModelMultipleChoiceFilter ๊ฒฝ์šฐ URL์€ field_name=tag1&field_name=tag2 ์—ฌ์•ผ ํ•˜์ง€๋งŒ ํƒœ๊ทธ๊ฐ€ ๋งŽ์•„ URL์ด ๋งค์šฐ ๊ธธ์–ด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” URL์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

ํƒœ๊ทธ๋Š” ์ผ๋ จ์˜ ๊ทœ์น™์„ ์‚ฌ์šฉํ•˜์—ฌ django-taggit์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋˜์–ด ๋ชจ๋“  ํƒœ๊ทธ๋ฅผ ํฌํ•จํ•˜๋Š” ๋‹จ์ผ ๋ฌธ์ž์—ด์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด์จŒ๋“  lookup_expr ์˜ ModelMultipleChoiceFilter ๋Š” ํ™•์‹คํžˆ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค!

๊ฐ„๋‹จํžˆ ์‚ดํŽด๋ณด๋ฉด Taggit์˜ TagsField ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•จ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ csv ๊ตฌ๋ฌธ ๋ถ„์„ ๋™์ž‘์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

class TagsFilter(CharFilter):
    field_class = taggit.forms.TagsField

    def __init__(self, *args, **kwargs):
        kwargs.setdefault('lookup_expr', 'in')


class MyFilterSet(FilterSet):
    tags = TagsFilter(name='tags__name')

    class Meta:
        model = MyModel
GET http://localhost/api/my-model?tags=a,b,c,d

์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•  ์ ์€ ์ด๊ฒƒ์ด in ์กฐํšŒ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋‹น์‹ ์ด ์ฐพ๊ณ  ์žˆ๋Š” ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๋Š” ์†”๋ฃจ์…˜์ด ์•„๋‹™๋‹ˆ๋‹ค.

Django Taggit์— ๋Œ€ํ•œ ํŠน์ • ํ•„ํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์„ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค. ํ›Œ๋ฅญํ•œ ํŒจํ‚ค์ง€์ด๊ธด ํ•˜์ง€๋งŒ์š”.

๊ถ๊ทน์ ์œผ๋กœ ํ”„๋กœ์ ํŠธ ์ˆ˜์ค€ ํ•„ํ„ฐ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ดœ์ฐฎ์€ ์š”์ง€๋Š” ๋จผ ๊ธธ์„ ๊ฐˆ ๊ฒƒ์ž…๋‹ˆ๋‹ค. (Google์€ ๊ทธ๋Ÿฐ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค.)

A+ ํ’€ ๋ฆฌํ€˜์ŠคํŠธ๊ฐ€ ๋‚˜ํƒ€๋‚˜๋ฉด ๊ธฐ์˜๊ฒŒ ์ƒ๊ฐํ•˜์ง€๋งŒ, ๊ทธ ์™ธ์—๋Š” ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋Š” ๊ฒƒ์œผ๋กœ ๋งˆ๋ฌด๋ฆฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์•Œ๊ฒ ์Šต๋‹ˆ๋‹ค. ์ถฉ๋ถ„ํžˆ ๊ณต์ •ํ•ฉ๋‹ˆ๋‹ค. ModelMultipleChoiceFilter lookup_expr ์ง€์›์€ ์–ด๋–ป์Šต๋‹ˆ๊นŒ?

@stantond PR์„ ๋ณด๋‹ˆ

๋‚˜๋Š” ํ•  ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค. ๋ถˆํ–‰ํžˆ๋„ ์ €๋Š” ์ˆ™๋ จ๋œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์•„๋‹ˆ๋ผ ๋”๋“ฌ๊ฑฐ๋ฆฌ๋Š” PM์ž…๋‹ˆ๋‹ค!

+1

์ตœ์‹  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ ์ž‘์—… ์˜ˆ:

from taggit.forms import TagField
from django_filters.views import FilterView

class TagFilter(django_filters.CharFilter):
    field_class = TagField

    def __init__(self, *args, **kwargs):
        kwargs.setdefault('lookup_expr', 'in')
        super().__init__(*args, **kwargs)


class MyFilter(django_filters.FilterSet):
    tags = TagFilter(field_name='tags__name')

    class Meta:
        model = MyModel

๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด name ํ•„๋“œ ๋Œ€์‹  ํƒœ๊ทธ์˜ slug ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. Taggit์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์Šฌ๋Ÿฌ๊ทธ๋ฅผ ์†Œ๋ฌธ์ž๋กœ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค.

ํ•˜๋‚˜ ์ด์ƒ์˜ ๊ณต๋ฐฑ์ด ํฌํ•จ๋œ ๋‹จ์ผ ํƒœ๊ทธ๋กœ ํ•„ํ„ฐ๋ฅผ ์ง€์›ํ•˜๋ ค๋Š” ๊ฒฝ์šฐ ์‚ฌ์šฉ์ž ์ •์˜ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ https://github.com/carltongibson/django-filter/issues/460#issuecomment -507218839์—์„œ ์†”๋ฃจ์…˜์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

from django import forms
from django.utils.translation import gettext as _

from taggit.utils import parse_tags


class TagField(forms.CharField):

    def clean(self, value):
        value = super().clean(value)

        if "," not in value and '"' not in value and value:
            return [value]

        try:
            return parse_tags(value)
        except ValueError:
            raise forms.ValidationError(
                _("Please provide a comma-separated list of tags.")
            )

์ฝ”๋“œ๋Š” taggit/forms.py ์—์„œ ์ถ”์ถœ๋ฉ๋‹ˆ๋‹ค.

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