Django-filter: FilterSet์ด ์ธ์‹ํ•  ์ˆ˜ ์—†๋Š” ํ•„๋“œ ์œ ํ˜• ImageField์— ๋Œ€ํ•œ '์ •ํ™•ํ•œ' ์กฐํšŒ๋กœ ํ•„๋“œ '์ด๋ฏธ์ง€'๋ฅผ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค...

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

์•ˆ๋…•!
์ด ๋ฌธ์ œ๊ฐ€ ์—ฌ๊ธฐ์—์„œ ์ด๋ฏธ ํ•ด๊ฒฐ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ์ ์ ˆํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ์ƒ์ ์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ณ  ์ฟผ๋ฆฌํ•  ๋•Œ ํ‘œ์‹œํ•  image = models.ImageField ํ•„๋“œ๋„ ํฌํ•จํ•˜๋Š” Store ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š” ๋ชจ๋ธ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์„œ์—์„œ ๋ชจ๋“  ๊ฒƒ์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋‚ด ์ œ์™ธ์™€ ๋‚ด๊ฐ€ ํ•„ํ„ฐ๋งํ•˜๋Š” ํ•„๋“œ๋ฅผ ๋ฌด์‹œํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

class StoreFilter(django_filters.FilterSet):
    class Meta:
        model = Store
        exclude = ['image']
        fields = {
            'name': ['exact', 'contains'],
            'created': ['exact', 'year__gt'],
        }

์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ํ•„ํ„ฐ๋งํ•˜๋ ค๊ณ  ํ•˜๋Š” ๊ฒƒ์ด๋ฉฐ AssertionError๊ฐ€ ๊ณ„์† ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ๋ฌด์—‡์„ ๋†“์น˜๊ณ  ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚ด models.py์—์„œ ์ด๋ฏธ์ง€ ๋ผ์ธ์— ์ฃผ์„์„ ๋‹ค๋Š” ์ฆ‰์‹œ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์นœ์• ํ•˜๋Š”

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

์•ˆ๋…•ํ•˜์„ธ์š” @msbt - ์—ฌ๊ธฐ์— ์ผ๋ถ€ ์ •๋ณด๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋น ๋ฅธ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ–ˆ๋Š”๋ฐ ์–ธ๊ธ‰๋œ AssertionError ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ์ด๋ฏธ์ง€ ํ•„๋“œ์— ๋Œ€ํ•œ ํ•„ํ„ฐ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

```ํŒŒ์ด์ฌ

๋ชจ๋ธ

django.db ๊ฐ€์ ธ์˜ค๊ธฐ ๋ชจ๋ธ์—์„œ

ํด๋ž˜์Šค ์Šคํ† ์–ด(models.Model):
์ด๋ฆ„ = ๋ชจ๋ธ.CharField(์ตœ๋Œ€ ๊ธธ์ด=80)
์ƒ์„ฑ = models.DateField()
์ด๋ฏธ์ง€ = ๋ชจ๋ธ.์ด๋ฏธ์ง€ํ•„๋“œ()

ํ•„ํ„ฐ

django_filters ๊ฐ€์ ธ์˜ค๊ธฐ

ํด๋ž˜์Šค StoreFilter(django_filters.FilterSet):
ํด๋ž˜์Šค ๋ฉ”ํƒ€:
๋ชจ๋ธ = ๋งค์žฅ
์ œ์™ธ = ['์ด๋ฏธ์ง€']
ํ•„๋“œ = {
'์ด๋ฆ„': ['์ •ํ™•ํ•œ', 'ํฌํ•จ'],
'์ƒ์„ฑ๋จ': ['์ •ํ™•ํ•œ', '์—ฐ๋„__gt'],
}

์ฝ˜์†” ์ถœ๋ ฅ

[8]์—์„œ: StoreFilter.base_filters
์•„์›ƒ[8]:
OrderedDict([('์ด๋ฆ„',),
('์ด๋ฆ„__ํฌํ•จ',),
('๋งŒ๋“ค์–ด์ง„',),
('์ƒ์„ฑ๋œ__๋…„__gt',)])
````

์ „์ฒด ๋ชจ๋ธ ๋ฐ ํ•„ํ„ฐ ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์ •์ œ๋œ ์˜ˆ๊ฐ€ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

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

์•ˆ๋…•ํ•˜์„ธ์š” @msbt - ์—ฌ๊ธฐ์— ์ผ๋ถ€ ์ •๋ณด๊ฐ€ ๋ˆ„๋ฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋น ๋ฅธ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ–ˆ๋Š”๋ฐ ์–ธ๊ธ‰๋œ AssertionError ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋“ฏ์ด ์ด๋ฏธ์ง€ ํ•„๋“œ์— ๋Œ€ํ•œ ํ•„ํ„ฐ๊ฐ€ ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

```ํŒŒ์ด์ฌ

๋ชจ๋ธ

django.db ๊ฐ€์ ธ์˜ค๊ธฐ ๋ชจ๋ธ์—์„œ

ํด๋ž˜์Šค ์Šคํ† ์–ด(models.Model):
์ด๋ฆ„ = ๋ชจ๋ธ.CharField(์ตœ๋Œ€ ๊ธธ์ด=80)
์ƒ์„ฑ = models.DateField()
์ด๋ฏธ์ง€ = ๋ชจ๋ธ.์ด๋ฏธ์ง€ํ•„๋“œ()

ํ•„ํ„ฐ

django_filters ๊ฐ€์ ธ์˜ค๊ธฐ

ํด๋ž˜์Šค StoreFilter(django_filters.FilterSet):
ํด๋ž˜์Šค ๋ฉ”ํƒ€:
๋ชจ๋ธ = ๋งค์žฅ
์ œ์™ธ = ['์ด๋ฏธ์ง€']
ํ•„๋“œ = {
'์ด๋ฆ„': ['์ •ํ™•ํ•œ', 'ํฌํ•จ'],
'์ƒ์„ฑ๋จ': ['์ •ํ™•ํ•œ', '์—ฐ๋„__gt'],
}

์ฝ˜์†” ์ถœ๋ ฅ

[8]์—์„œ: StoreFilter.base_filters
์•„์›ƒ[8]:
OrderedDict([('์ด๋ฆ„',),
('์ด๋ฆ„__ํฌํ•จ',),
('๋งŒ๋“ค์–ด์ง„',),
('์ƒ์„ฑ๋œ__๋…„__gt',)])
````

์ „์ฒด ๋ชจ๋ธ ๋ฐ ํ•„ํ„ฐ ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ ‡์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋ฌธ์ œ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ์ •์ œ๋œ ์˜ˆ๊ฐ€ ๋„์›€์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์•ˆ๋…•, ๋‹ค์‹œ ๋Œ์•„์™€์ค˜์„œ ๊ณ ๋งˆ์›Œ! ๋‚ด๊ฐ€ ๋ฌด์—‡์„ ์ž˜๋ชปํ–ˆ๋Š”์ง€ ์•Œ์•„๋‚ผ ์‹œ๊ฐ„์„ ์กฐ๊ธˆ๋งŒ ๋” ์ฃผ์„ธ์š”. ์ดˆ๋ณด์ ์ธ ์‹ค์ˆ˜๋ผ๋ฉด ๋‹นํ™ฉ์Šค๋Ÿฌ์šธ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ;)

์•ˆ๋…•ํ•˜์„ธ์š” @msbt - ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์•Œ์•„๋ƒˆ์Šต๋‹ˆ๊นŒ, ์•„๋‹ˆ๋ฉด ๋‹ซ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ง€๊ธˆ์€ ์‹œ๊ฐ„์ด ์—†์œผ๋‹ˆ ๋‹ซ๊ณ  ๋‹ค์‹œ ์‹œ๋„ํ•˜๋‹ค๊ฐ€ ๋ง‰ํžˆ๋ฉด ๋‹ค์‹œ ๋ฐฉ๋ฌธํ•˜๋„๋ก ํ• ๊ฒŒ์š” ;)

@msbt ์ด ๋ฌธ์ œ์— ๋Œ€ํ•œ ์•„์ด๋””์–ด๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ๊ฐ™์€ ๊ฒƒ์„ ๊ฐ€์ง€๊ณ ์žˆ๋‹ค

@georgezouq ๋‘๋ ค์›Œํ•˜์ง€ ์•Š๊ณ  ๋‹ค๋ฅธ ์ด์œ ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ํฌ๊ธฐํ•˜๊ณ  ์†”๋ฃจ์…˜์„ ์ฐพ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค

์—ญ์ถ”์  ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค. ๐Ÿ˜€

Internal Server Error: /stadiums/
Traceback (most recent call last):
  File "C:\Users\default_user\PycharmProjects\pina_colada\venv\lib\site-packages\django\core\handlers\exception.py", line 34, in inner
    response = get_response(request)
  File "C:\Users\default_user\PycharmProjects\pina_colada\venv\lib\site-packages\django\core\handlers\base.py", line 126, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "C:\Users\default_user\PycharmProjects\pina_colada\venv\lib\site-packages\django\core\handlers\base.py", line 124, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\default_user\PycharmProjects\pina_colada\venv\lib\site-packages\django\views\generic\base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\*\PycharmProjects\pina_colada\venv\lib\site-packages\django\views\generic\base.py", line 88, in dispatch
    return handler(request, *args, **kwargs)
  File "C:\Users\*\PycharmProjects\pina_colada\venv\lib\site-packages\django_filters\views.py", line 77, in get
    filterset_class = self.get_filterset_class()
  File "C:\Users\*\PycharmProjects\pina_colada\venv\lib\site-packages\django_filters\views.py", line 35, in get_filterset_class
    return filterset_factory(model=self.model, fields=self.filterset_fields)
  File "C:\Users\*\PycharmProjects\pina_colada\venv\lib\site-packages\django_filters\filterset.py", line 459, in filterset_factory
    (FilterSet,), {'Meta': meta})
  File "C:\Users\default_user\PycharmProjects\pina_colada\venv\lib\site-packages\django_filters\filterset.py", line 71, in __new__
    new_class.base_filters = new_class.get_filters()
  File "C:\Users\default_user\PycharmProjects\pina_colada\venv\lib\site-packages\django_filters\filterset.py", line 345, in get_filters
    filters[filter_name] = cls.filter_for_field(field, field_name, lookup_expr)
  File "C:\Users\default_user\PycharmProjects\pina_colada\venv\lib\site-packages\django_filters\filterset.py", line 377, in filter_for_field
    ) % (cls.__name__, field_name, lookup_expr, field.__class__.__name__)
AssertionError: StadiumFilterSet resolved field 'graphic' with 'exact' lookup to an unrecognized field type FileField. Try adding an override to 'Meta.filter_overrides'. See: https://django-filter.readthedocs.io/en/master/ref/filterset.html#customise-filter-generation-with-filter-overrides
[13/Dec/2018 08:23:58] "GET /stadiums/?page=1 HTTP/1.1" 500 108150
class StadiumFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(lookup_expr='iexact')

    class Meta:
        model = Stadium
        exclude = ['graphic']
        filter_overrides = {
            models.FileField: {
                'filter_class': django_filters,
                'extra': lambda f: {
                    'lookup_expr': 'icontains',
                },
            },
        }

@carltongibson ์ข€ ๋ด์ฃผ์„ธ์š”

์ผ๋ฐ˜ ๋ณด๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์žฌ์ •์˜๋ฅผ ๋ฌด์‹œํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ผ์‹œ์ ์œผ๋กœ ๋‚ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์ง€๋งŒ ๋‚ด ๊ณ ๊ฐ์€ ํ•„ํ„ฐ์˜ ํŠน์ˆ˜์„ฑ์œผ๋กœ ์ธํ•ด ๋‚˜๋ฅผ ๊ท€์ฐฎ๊ฒŒํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ ์ข€ ๋ด์ฃผ์‹œ๊ฒ ์–ด์š”?

urlpatterns = [
    path('', views.StadiumFilterView.as_view(model=Stadium,
                                             filterset_fields=['name', 'country']), name="stadium_index"),
]

fields, exclude, filter_overrides in Meta๋Š” ์ด AssertionError ์˜ค๋ฅ˜๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. FilterView + filter_class = MyFilterSet ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ํ•„๋“œ๋ฅผ ์ œ์™ธํ•˜๋ ค๋ฉด ๋ณด๊ธฐ ์•„๋ž˜์— filter_fields๋ฅผ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด def filter_for_field(cls, f, name, lookup_expr='exact') ๊ฐ€ ๋ชจ๋“  ํ•„๋“œ์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

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