django-autocomplete-light and django-filter Forward Filter Selection

1.8k Views Asked by At

I've implemented django-autocomplete-light and django-filter together for two fields (foreign keys referencing related fields in two other models:

field__field = ModelMultipleChoiceFilter(queryset=Model.objects.all(),
              widget=autocomplete.ModelSelect2Multiple(url='url'))

field2__field2 = ModelMultipleChoiceFilter(queryset=SecondModel.objects.all(),
                  widget=autocomplete.ModelSelect2Multiple(url='url2'))

When I try to use DAL's forward ability...

field__field = ModelMultipleChoiceFilter(queryset=Model.objects.all(),
              widget=autocomplete.ModelSelect2Multiple(url='url'))

field2__field2 = ModelMultipleChoiceFilter(queryset=SecondModel.objects.all(),
                  widget=autocomplete.ModelSelect2Multiple(url='url2', forward=['field__field']))

...nothing happens. The autocomplete boxes do not cascade.

I think it might have to do with the fact that django-filter requires the queryset to be called explicitly.

How do I implement forward effectively?

Edit:

views.py

class FieldAutocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = Model.objects.all()
        if self.q:
            qs = qs.filter(field__icontains=self.q)
        return qs

class Field2Autocomplete(autocomplete.Select2QuerySetView):
    def get_queryset(self):
        qs = SecondModel.objects.all()
        field = self.forwarded.get('field', None)
        if field:
            qs = qs.filter(field=field)
        if self.q:
            qs = qs.filter(field2__icontains=self.q)
        return qs

In addition to the views, I also use Field to allow for the related name...

field2__field2 = ModelMultipleChoiceFilter(queryset=SecondModel.objects.all(),
                      widget=autocomplete.ModelSelect2Multiple(url='url2', forward=(Field('field_field', 'field')))

...but this results in 'Field' object is not iterable. Here is the traceback:

Traceback:

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\core\handlers\exception.py" in inner
  41.             response = get_response(request)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\core\handlers\base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\core\handlers\base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "C:\Users\username\repos\mysite\alerts\views.py" in search
  79.     return render(request, 'search.html', context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\shortcuts.py" in render
  30.     content = loader.render_to_string(template_name, context, request, using=using)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\loader.py" in render_to_string
  68.     return template.render(context, request)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\backends\django.py" in render
  66.             return self.template.render(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in render
  207.                     return self._render(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in _render
  199.         return self.nodelist.render(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in render
  990.                 bit = node.render_annotated(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in render_annotated
  957.             return self.render(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\loader_tags.py" in render
  177.             return compiled_parent._render(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in _render
  199.         return self.nodelist.render(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in render
  990.                 bit = node.render_annotated(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in render_annotated
  957.             return self.render(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\loader_tags.py" in render
  72.                 result = block.nodelist.render(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in render
  990.                 bit = node.render_annotated(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in render_annotated
  957.             return self.render(context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in render
  1046.         return render_value_in_context(output, context)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\template\base.py" in render_value_in_context
  1024.     value = force_text(value)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\utils\encoding.py" in force_text
  76.                     s = six.text_type(s)

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\utils\html.py" in <lambda>
  385.         klass.__str__ = lambda self: mark_safe(klass_str(self))

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\forms\boundfield.py" in __str__
  41.         return self.as_widget()

File "C:\Users\username\python\envs\mysite\lib\site-packages\django\forms\boundfield.py" in as_widget
  127.             **kwargs

File "C:\Users\username\python\envs\mysite\lib\site-packages\dal\widgets.py" in render
  151.         conf = self.render_forward_conf(attrs['id'])

File "C:\Users\username\python\envs\mysite\lib\site-packages\dal\widgets.py" in render_forward_conf
  96.                 ) + \

Exception Type: TypeError at /search
Exception Value: 'Field' object is not iterable

The view setup works for autocomplete on a form (it forwards properly). But when I try to use it as a widget to a filter, it doesn't work.

1

There are 1 best solutions below

0
On

I had the 'Field' object is not iterable error and it has an easy solution. The 'forward' argument expects a tuple, but declared as in your code is just a Field object. So, the solution is this:

field2__field2 = ModelMultipleChoiceFilter(queryset=SecondModel.objects.all(),
                      widget=autocomplete.ModelSelect2Multiple(url='url2', forward=(Field('field_field', 'field'),)))

Note the comma which makes the difference between object and tuple.