Django-filter: [2.1.0] BaseCSVWidget.value_from_datadict β€” AttributeError: 'list' κ°œμ²΄μ— 'split' 속성이 μ—†μŠ΅λ‹ˆλ‹€.

에 λ§Œλ“  2019λ…„ 07μ›” 12일  Β·  15μ½”λ©˜νŠΈ  Β·  좜처: carltongibson/django-filter

λ‚˜λŠ” ...

Traceback (most recent call last):
  [..]
  File "/usr/local/lib/python3.7/site-packages/django/forms/forms.py", line 393, in _clean_fields
    value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
  File "/usr/local/lib/python3.7/site-packages/django_filters/widgets.py", line 201, in value_from_datadict
    return value.split(',')
AttributeError: 'list' object has no attribute 'split'

그리고 κ·Έ μ½”λ“œλŠ” ...
https://github.com/carltongibson/django-filter/blob/1f47e36b614724a8735e0457fa511dcaf5448481/django_filters/widgets.py#L195 -L202
... super().value_from_datadict(data, files, name) κ°€ λͺ©λ‘μ„ λ°˜ν™˜ν•˜λŠ” 것과 κ΄€λ ¨ν•˜μ—¬ κ°•λ ₯ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 더 디버깅해야 ν•˜μ§€λ§Œ μ—¬κΈ°μ—μ„œ 무슨 일이 μΌμ–΄λ‚˜κ³  μžˆλŠ”μ§€ 이미 μ•Œκ³  μžˆμ„ μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

κ°€μž₯ μœ μš©ν•œ λŒ“κΈ€

방금 이 였λ₯˜κ°€ λ°œμƒν–ˆκ³  이에 λŒ€ν•œ μ„€λͺ…은 이 μŠ€λ ˆλ“œμ— λ¬»ν˜€ μžˆμœΌλ―€λ‘œ μš”μ•½ν•˜κ³  미래 λ…μžλ₯Ό μœ„ν•΄ κΈ΄ 검색을 μ €μž₯ν•©λ‹ˆλ‹€.

ManyToMany 보기 μ„ΈνŠΈμ˜ filterset_fields 에 μ„ μ–Έλœ ν•„λ“œλŠ” in λ₯Ό 포함 ν•  수 μ—†μŠ΅λ‹ˆλ‹€ .

λŸ°νƒ€μž„ μ‹œ κ²½κ³ λŠ” 맀우 κ°μ‚¬ν•˜κ² μŠ΅λ‹ˆλ‹€.

λͺ¨λ“  15 λŒ“κΈ€

μ•ˆλ…•ν•˜μ„Έμš” @mosebμž…λ‹ˆλ‹€. μ‚¬μš© 쀑인 FilterSet μ½”λ“œλ₯Ό 뢙여넣을 수 μžˆμŠ΅λ‹ˆκΉŒ? μ—­μΆ”μ μ˜ λ§ˆμ§€λ§‰ λͺ‡ 쀄은 이 μ˜ˆμ™Έκ°€ λ°œμƒν•œ 이유λ₯Ό κ²°μ •ν•˜κΈ°μ— μΆ©λΆ„ν•©λ‹ˆλ‹€.

전체 역좔적:

Traceback (most recent call last):
  File "/usr/local/lib/python3.7/wsgiref/handlers.py", line 137, in run
    self.result = application(self.environ, self.start_response)
  File "/usr/local/lib/python3.7/site-packages/django/contrib/staticfiles/handlers.py", line 65, in __call__
    return self.application(environ, start_response)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/wsgi.py", line 141, in __call__
    response = self.get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 75, in get_response
    response = self._middleware_chain(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
    response = response_for_exception(request, exc)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
    response = response or self.get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
    response = response_for_exception(request, exc)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
    response = response or self.get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
    response = response_for_exception(request, exc)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
    response = response or self.get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
    response = response_for_exception(request, exc)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
    response = response or self.get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
    response = response_for_exception(request, exc)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
    response = response or self.get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
    response = response_for_exception(request, exc)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
    response = response or self.get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
    response = response_for_exception(request, exc)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django_global_request/middleware.py", line 15, in __call__
    return self.get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
    response = response_for_exception(request, exc)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
    response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
    response = get_response(request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 145, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 143, in _get_response
    response = response.render()
  File "/usr/local/lib/python3.7/site-packages/django/template/response.py", line 106, in render
    self.content = self.rendered_content
  File "/usr/local/lib/python3.7/site-packages/rest_framework/response.py", line 72, in rendered_content
    ret = renderer.render(self.data, accepted_media_type, context)
  File "/usr/local/lib/python3.7/site-packages/rest_framework/renderers.py", line 733, in render
    context = self.get_context(data, accepted_media_type, renderer_context)
  File "/usr/local/lib/python3.7/site-packages/rest_framework/renderers.py", line 710, in get_context
    'filter_form': self.get_filter_form(data, view, request),
  File "/usr/local/lib/python3.7/site-packages/rest_framework/renderers.py", line 642, in get_filter_form
    html = backend().to_html(request, queryset, view)
  File "/usr/local/lib/python3.7/site-packages/rest_framework_filters/backends.py", line 52, in to_html
    return super().to_html(request, queryset, view)
  File "/usr/local/lib/python3.7/site-packages/django_filters/rest_framework/backends.py", line 105, in to_html
    return template.render(context, request)
  File "/usr/local/lib/python3.7/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 171, in render
    return self._render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 163, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.7/site-packages/crispy_forms/templatetags/crispy_forms_tags.py", line 199, in render
    c = self.get_render(context).flatten()
  File "/usr/local/lib/python3.7/site-packages/crispy_forms/templatetags/crispy_forms_tags.py", line 118, in get_render
    actual_form.form_html = helper.render_layout(actual_form, node_context, template_pack=self.template_pack)
  File "/usr/local/lib/python3.7/site-packages/crispy_forms/helper.py", line 308, in render_layout
    template_pack=template_pack
  File "/usr/local/lib/python3.7/site-packages/crispy_forms/layout.py", line 140, in render
    return self.get_rendered_fields(form, form_style, context, template_pack, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/crispy_forms/layout.py", line 104, in get_rendered_fields
    for field in self.fields
  File "/usr/local/lib/python3.7/site-packages/crispy_forms/layout.py", line 104, in <genexpr>
    for field in self.fields
  File "/usr/local/lib/python3.7/site-packages/crispy_forms/utils.py", line 148, in render_field
    html = template.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/backends/django.py", line 61, in render
    return self.template.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 171, in render
    return self._render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 163, in _render
    return self.nodelist.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/defaulttags.py", line 309, in render
    return nodelist.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/defaulttags.py", line 309, in render
    return nodelist.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 937, in render
    bit = node.render_annotated(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 904, in render_annotated
    return self.render(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/defaulttags.py", line 302, in render
    match = condition.eval(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/defaulttags.py", line 876, in eval
    return self.value.resolve(context, ignore_failures=True)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 671, in resolve
    obj = self.var.resolve(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 796, in resolve
    value = self._resolve_lookup(context)
  File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 837, in _resolve_lookup
    current = getattr(current, bit)
  File "/usr/local/lib/python3.7/site-packages/django/forms/boundfield.py", line 74, in errors
    return self.form.errors.get(self.name, self.form.error_class())
  File "/usr/local/lib/python3.7/site-packages/django/forms/forms.py", line 180, in errors
    self.full_clean()
  File "/usr/local/lib/python3.7/site-packages/django/forms/forms.py", line 381, in full_clean
    self._clean_fields()
  File "/usr/local/lib/python3.7/site-packages/django/forms/forms.py", line 393, in _clean_fields
    value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
  File "/usr/local/lib/python3.7/site-packages/django_filters/widgets.py", line 201, in value_from_datadict
    return value.split(',')
AttributeError: 'list' object has no attribute 'split'
[12/Jul/2019 13:49:06] "GET /XXXXXXXX/?ordering=first_name HTTP/1.1" 500 59

django-rest-frameworkκ°€ μ½”λ“œλ₯Ό μƒμ„±ν•˜λŠ” λͺ©λ‘μ„ νƒμƒ‰ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

μ•ˆλ…•ν•˜μ„Έμš” @mosebμž…λ‹ˆλ‹€. μ‚¬μš© 쀑인 FilterSet μ½”λ“œλ₯Ό 뢙여넣을 수 μžˆμŠ΅λ‹ˆκΉŒ?

μ†”μ§νžˆ λ§ν•΄μ„œ, 아직 μ½”λ“œμ˜ ν•΄λ‹Ή μ˜μ—­μ—μ„œ 아무 것도 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€. 그것은 λͺ¨λ‘ DRF에 μ˜ν•œ 것일 수 μžˆμŠ΅λ‹ˆλ‹€. 아직 ν™•μ‹€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
λ‚΄ 버그 λ³΄κ³ μ„œκ°€ 이상적이지 μ•Šλ‹€λŠ” 것을 μ•Œκ³  μžˆμ§€λ§Œ ν˜„μž¬λ‘œμ„œλŠ” κ°€μž₯ μ’‹μŠ΅λ‹ˆλ‹€. μ£„μ†‘ν•©λ‹ˆλ‹€!

API λ³΄κΈ°μ—λŠ” filterset_class λ˜λŠ” filterset_fields λ˜λŠ” 이전 λ²„μ „μ˜ django-filterλ₯Ό μ‚¬μš©ν•˜λŠ” 경우 filter_class 및 filter_fields κ°€ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

filter_class μ‚¬μš©μ„ μ°Ύμ•˜μŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ django-filter 2.0으둜의 λ§ˆμ΄κ·Έλ ˆμ΄μ…˜ 이 λκΉŒμ§€ μ œλŒ€λ‘œ μˆ˜ν–‰λ˜μ§€ μ•Šμ•˜λ‹€λŠ” 것을 μ•Œκ²Œ 된 것 κ°™μŠ΅λ‹ˆλ‹€. μ‹œμ›ν•œ!
κ°œλ…μ μœΌλ‘œ django-filterκ°€ pre-2.x 남은 μŒμ‹μ„ κ°μ§€ν•˜κ³  이에 λŒ€ν•΄ κ²½κ³ ν•˜λŠ” 것을 λ§‰λŠ” 것이 μžˆμŠ΅λ‹ˆκΉŒ? κ²½κ³ ν•˜μ§€λ§Œ λ‚΄κ°€ λ†“μ³€μŠ΅λ‹ˆκΉŒ? ν’€ λ¦¬ν€˜μŠ€νŠΈμ— λŒ€ν•œ ν™˜μ˜ μΆ”κ°€ 사항에 λŒ€ν•œ μ½”λ“œ κ²½κ³ κ°€ μžˆμŠ΅λ‹ˆκΉŒ?

v2.0은 κΈ°μ‘΄ μ‚¬μš© 쀑단 κ²½κ³ λ₯Ό 많이 μ œκ±°ν–ˆμœΌλ―€λ‘œ v1.0에 λŒ€ν•΄ ν…ŒμŠ€νŠΈ μŠ€μœ„νŠΈλ₯Ό μ‹€ν–‰ν•œ λ‹€μŒ django-filter의 v1.1에 λŒ€ν•΄ μ‹€ν–‰ν•΄ λ³Ό 수 μžˆμŠ΅λ‹ˆλ‹€.

μ—…λ°μ΄νŠΈν•˜λ©΄ μ €μ ˆλ‘œ ν•΄κ²°λœλ‹€κ³  κ°€μ •ν•©λ‹ˆλ‹€. 그렇지 μ•ŠμœΌλ©΄ λ‹€μ‹œ μ˜€μ‹­μ‹œμ˜€.

https://github.com/moseb/django-filter-issue-1103-demo에 μž¬ν˜„ κ°€λŠ₯ν•œ 문제의 데λͺ¨κ°€ μžˆμŠ΅λ‹ˆλ‹€. 이 문제λ₯Ό λ‹€μ‹œ μ—¬λŠ” 것을 κ³ λ €ν•˜μ‹­μ‹œμ˜€. κ°μ‚¬ν•©λ‹ˆλ‹€!

μ•„, 이것은 ModelMultipleChoiceFilter 이 CSV mixinκ³Ό ν˜Έν™˜λ˜μ§€ μ•ŠλŠ” 것과 in μ‘°νšŒμ™€ 관련이 μžˆμŠ΅λ‹ˆλ‹€. 여기에 두 가지 λ³„κ°œμ˜ κ΄€λ ¨ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

객관식 ν•„ν„°κ°€ 이미 μœ μ‚¬ν•œ λ™μž‘μ„ μ œκ³΅ν•˜λ―€λ‘œ m2m ν•„λ“œμ— λŒ€ν•΄ in μ‘°νšŒκ°€ ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

μ•ˆλ…•!

μ•„, 이것은 ModelMultipleChoiceFilter 이 CSV mixinκ³Ό ν˜Έν™˜λ˜μ§€ μ•ŠλŠ” 것과 in μ‘°νšŒμ™€ 관련이 μžˆμŠ΅λ‹ˆλ‹€. 여기에 두 가지 λ³„κ°œμ˜ κ΄€λ ¨ λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

GitHub에 μ΄λŸ¬ν•œ λ¬Έμ œμ— λŒ€ν•œ κΈ°μ‘΄ 티켓이 μžˆμŠ΅λ‹ˆκΉŒ?

μœ„μ—μ„œ μ–ΈκΈ‰ν•œ κ²ƒμ²˜λŸΌ BaseCSVWidget.value_from_datadict λ₯Ό 더 κ°•λ ₯ν•˜κ²Œ λ§Œλ“œλŠ” κ²ƒλ§ŒμœΌλ‘œλŠ” λ¬Έμ œκ°€ ν•΄κ²°λ˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆκΉŒ? (아직 문제λ₯Ό μ™„μ „νžˆ μ΄ν•΄ν•˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.)

객관식 ν•„ν„°κ°€ 이미 μœ μ‚¬ν•œ λ™μž‘μ„ μ œκ³΅ν•˜λ―€λ‘œ m2m ν•„λ“œμ— λŒ€ν•΄ in μ‘°νšŒκ°€ ν•„μš”ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

in λ₯Ό μ‚¬μš©ν•˜λ©΄ exact μ΄μƒμ˜ μ—¬λŸ¬ 값을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. Γ¬n λ₯Ό μ‚¬μš©ν•  수 μ—†λŠ” 경우 μ—¬λŸ¬ 값을 ν™•μΈν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν•©λ‹ˆκΉŒ?

μΆ”μ‹ : 이 티켓을 λ‹€μ‹œ μ—΄ 수 μžˆμŠ΅λ‹ˆκΉŒ?

μœ„μ—μ„œ μ–ΈκΈ‰ν•œ κ²ƒμ²˜λŸΌ BaseCSVWidget.value_from_datadict λ₯Ό 더 κ°•λ ₯ν•˜κ²Œ λ§Œλ“œλŠ” κ²ƒλ§ŒμœΌλ‘œλŠ” λ¬Έμ œκ°€ ν•΄κ²°λ˜μ§€ μ•ŠλŠ” 것 κ°™μŠ΅λ‹ˆκΉŒ? (아직 문제λ₯Ό μ™„μ „νžˆ μ΄ν•΄ν•˜μ§€ λͺ»ν–ˆμŠ΅λ‹ˆλ‹€.)

ν˜Ήμ‹œ. 값이 이미 λͺ©λ‘μ΄λ©΄ 계속 μ§„ν–‰ν•˜μ—¬ ν•΄λ‹Ή λͺ©λ‘μ„ λ°˜ν™˜ν•΄μ•Ό ν•©λ‹ˆλ‹€. 즉, CSV λ™μž‘μ„ SelectMultiple μœ„μ ―κ³Ό ν˜Όν•©ν•˜λŠ” 것이 합리적이지 μ•Šλ‹€κ³  μƒκ°ν•©λ‹ˆλ‹€.

in λ₯Ό μ‚¬μš©ν•˜λ©΄ exact μ΄μƒμ˜ μ—¬λŸ¬ 값을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. Γ¬n λ₯Ό μ‚¬μš©ν•  수 μ—†λŠ” 경우 μ—¬λŸ¬ 값을 ν™•μΈν•˜λ €λ©΄ μ–΄λ–»κ²Œ ν•΄μ•Ό ν•©λ‹ˆκΉŒ?

ModelMultipleChoiceFilter λŠ” Q κ°œμ²΄μ—μ„œ OR 쿼리λ₯Ό κ΅¬μ„±ν•©λ‹ˆλ‹€. λ”°λΌμ„œ /api/mymodel?m2m=a&m2m=b 와 같은 쿼리 λ¬Έμžμ—΄μ΄ μžˆλŠ” 경우 λ‹€μŒκ³Ό 같은 ν•„ν„° 호좜둜 λλ‚©λ‹ˆλ‹€.

MyModel.objects.filter(Q(m2m='a') | Q(m2m='b'))

2.1 λ¦΄λ¦¬μŠ€μ—μ„œλŠ” lookup_expr κ°€ 이제 각 Q κ°œμ²΄μ— μ μš©λ˜λ―€λ‘œ λ‹€μŒκ³Ό 같이 λ©λ‹ˆλ‹€.

MyModel.objects.filter(Q(m2m__in='a') | Q(m2m__in='b'))

μœ„μ˜ λ‚΄μš©μ€ μœ νš¨ν•˜μ§€ μ•ŠμœΌλ©° μ€‘λ‹¨λ˜μ§€λ§Œ contains 및 단일 κ°’μœΌλ‘œ μž‘λ™ν•˜λ„λ‘ μ˜λ„λœ 기타 μ‘°νšŒμ—λŠ” μ˜λ―Έκ°€ μžˆμŠ΅λ‹ˆλ‹€.

κ°„λ‹¨νžˆ λ§ν•΄μ„œ, μ—¬κΈ°μ„œ ν•΄μ•Ό ν•  일은 m2m ν•„λ“œμ— λŒ€ν•΄ exact 쑰회λ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.


μ—¬κΈ°μ—μ„œ ν•  일은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • 이미 λͺ©λ‘μΈ 경우 값을 λ°˜ν™˜ν•˜μ—¬ BaseCSVWidget κ°€ SelectMultiple 와 ν˜Έν™˜λ˜λ„λ‘ ν•©λ‹ˆλ‹€. λ˜λŠ” ν˜Έν™˜λ˜μ§€ μ•Šμ•„μ•Ό ν•˜λŠ” 경우 μ΅œμ†Œν•œ initμ—μ„œ μœ μš©ν•œ 였λ₯˜λ₯Ό μ œκ³΅ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • m2m에 λŒ€ν•΄ Meta.fields λ₯Ό μˆ˜μ •ν•©λ‹ˆλ‹€. ModelMultipleChoiceFilter in 쑰회λ₯Ό μƒμ„±ν•˜λŠ” 것은 μ˜λ―Έκ°€ μ—†μŠ΅λ‹ˆλ‹€. λ˜ν•œ λΆ€μšΈμ„ μ˜ˆμƒν•˜λŠ” isnull 와 같은 λ‹€λ₯Έ μ‘°νšŒμ— λŒ€ν•΄ μ–΄λ–€ 일이 λ°œμƒν•˜λŠ”μ§€ ν…ŒμŠ€νŠΈν•΄μ•Ό ν•©λ‹ˆλ‹€.

예, 이것은 μ—¬μ „νžˆ 버그 처럼 보이지 μ•Šμ§€λ§Œ λͺ¨λ“  μž‘λ™ 방식은 λ¬Έμ„œν™”λ˜μ§€ μ•Šμ€ 것 κ°™μŠ΅λ‹ˆλ‹€...

방금 이 였λ₯˜κ°€ λ°œμƒν–ˆκ³  이에 λŒ€ν•œ μ„€λͺ…은 이 μŠ€λ ˆλ“œμ— λ¬»ν˜€ μžˆμœΌλ―€λ‘œ μš”μ•½ν•˜κ³  미래 λ…μžλ₯Ό μœ„ν•΄ κΈ΄ 검색을 μ €μž₯ν•©λ‹ˆλ‹€.

ManyToMany 보기 μ„ΈνŠΈμ˜ filterset_fields 에 μ„ μ–Έλœ ν•„λ“œλŠ” in λ₯Ό 포함 ν•  수 μ—†μŠ΅λ‹ˆλ‹€ .

λŸ°νƒ€μž„ μ‹œ κ²½κ³ λŠ” 맀우 κ°μ‚¬ν•˜κ² μŠ΅λ‹ˆλ‹€.

@marcosox 쒋은 μƒκ°μž…λ‹ˆλ‹€. μΆ”κ°€ν•˜λŠ” PR을 λ³΄λ‹ˆ λ°˜κ°‘μŠ΅λ‹ˆλ‹€!

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰