Search code examples
djangoautocompletedjango-autocomplete-light

Can't save a django form with this autocomplete


I'm using autocomplete-light and for some reason this specific class is not working--I can't see any major differences between it and the working autocompletes. My VirtualHost contains a fk to a Host provided that Host.contain_virtuals=True

Here's my form:

class VirtualHostForm(ServerForm):
    def __init__(self, *args, **kwargs):
        super(VirtualHostForm, self).__init__(*args, **kwargs)

        self.helper.form_id = 'virtual_host_form'

    host = forms.ModelChoiceField(Host.objects.all(),
        widget=autocomplete_light.ChoiceWidget('HostAutocomplete'), 
        label='Associated Host'
    class Meta:
        model = Virtual
        fields = ServerForm.Meta.fields + ['host',]
        widgets = autocomplete_light.get_widgets_dict(Server)

I've tried two ways, each with their own errors:

class HostAutocomplete(autocomplete_light.AutocompleteBase):
    #registers autocomplete for hosts that can contain virtuals
    autocomplete_js_attributes = {'placeholder': 'Select a host'}
    widget_template='assets/subtemplates/autocomplete_remove.html',
    choice_template='assets/_autocomplete_choice.html',

    def choices_for_request(self):
        q = self.request.GET.get('q', '')
        hosts = Host.objects.values_list('name', flat=True)
        return hosts.filter(name__icontains=q, contain_virtuals=True).distinct()


autocomplete_light.register(HostAutocomplete)

This way, I get the error: 'NotImplementedType' object is not callable. That seemed to relate to not having a choices_for_values method (although some of my other Autocompletes don't) so I added:

def choices_for_values(self):
    choices = Host.objects.filter(id__in=self.values)
    return choices

(I don't really know what I'm doing here--I couldn't find much in the documentation, so I took my best guess).

That gave me a invalid literal for int() with base 10: which I guess means it's looking at the name, instead of the pk for a foreign key relationship? That's a guess.

It should be noted that all of the above attempts did not render the template-formatting correctly, but did at least give the correct options for the choices.

So finally I tried:

autocomplete_light.register(
    Host,
    autocomplete_light.AutocompleteModelTemplate,
    name='HostAutocomplete',
    widget_template='assets/subtemplates/autocomplete_remove.html',
    choice_template='assets/_autocomplete_choice.html',
    autocomplete_js_attributes={'placeholder': 'Type associated host'},
    search_fields=['name'],
    )

which saves (and contains the correct formatting) but does not filter the choices based on contain_virtuals=True; it just includes all possible hosts.

EDIT:

Thanks to @jpic's help below, this works:

class HostAutocomplete(autocomplete_light.AutocompleteModelTemplate):
    #registers autocomplete for hosts that can contain virtuals
    autocomplete_js_attributes = {'placeholder': 'Select a host'}
    choice_template='assets/_autocomplete_choice.html',

    def choices_for_request(self):
        q = self.request.GET.get('q', '')
        hosts = Host.objects.filter(contain_virtuals=True,name__icontains=q).distinct()
        return hosts

    def choices_for_values(self):
        choices = Host.objects.filter(id__in=self.values)
        return choices

autocomplete_light.register(Host, HostAutocomplete)

Solution

  • This is because you inherit from AutocompleteBase instead of AutocompleteModelBase ! You could use AutocompleteModelTemplate as well.

    Check out how Autocomplete design is explained in docs for v2 (that part doesn't change from v1 to v2): http://django-autocomplete-light.readthedocs.org/en/v2/autocomplete.html