Django-autocomplete-light: get_list() , allow value and text tuple.

Created on 28 Feb 2018  路  8Comments  路  Source: yourlabs/django-autocomplete-light

From the docs,

class CountryAutocompleteFromList(autocomplete.Select2GroupListView):
    def get_list(self):
        return [
            ("Country", ['France', 'Fiji', 'Finland', 'Switzerland'])
        ]

Can we supply value and text tuple, like so
I tried but not happening.

class CountryAutocompleteFromList(autocomplete.Select2GroupListView):
    def get_list(self):
        return [
            ("Country", [('france','France'),('fiji','Fiji'), ('finland','Finland'),( 'switzerland','Switzerland')])
        ]

enhancement question

All 8 comments

I have had a problem like this. I wanted to define the value in the <option> tag an not only the text as is done by Select2ListView. So I just adapted this one a bit:

class Select2DictView(autocomplete.Select2ListView):
    """Autocomplete from a dictionary of items rather than a QuerySet."""

    def get_dictionary(self):
        """
        Return the dictionary from which to autocomplete.
        - the key goes to the value attribute of the option tag
        - the value is the text enclosed by the option tag
        """
        return {}

    def get(self, request, *args, **kwargs):
        """"Return option list json response."""
        results = self.get_dictionary()
        create_option = []
        if self.q:
            results = [x for x in results if self.q.lower() in x.lower()]
            if hasattr(self, 'create'):
                create_option = [{
                    'id': self.q,
                    'text': 'Create "%s"' % self.q,
                    'create_id': True
                }]
        return HttpResponse(
            json.dumps(
                {'results': [dict(id=key, text=value) for key, value in results.items()] + create_option}
            ),
            content_type='application/json'
        )

class ExampleAutocompleteByDictView(Select2DictView):
    """ returns an equivalent of this html
    <select>
        <option value="1">one</option>
        <option value="2">two</option>
        <option value="3">one plus two</option>
    </select>
    """
    def get_dictionary(self) -> dict:
        return {
            1: "one",
            2: "two",
            3: "one plus two"
        }

Maybe the author of this awesome Django package could treat my little hacking as a blueprint. This approach of inheritance is definitely not DRY. But with a bit of refoactoring it should get implemented by chance?

if you want to refactor the widget/view part, why not try @Guilouf's pattern with widgets that make views ? it's currently in the gfk widget:

https://github.com/yourlabs/django-autocomplete-light/blob/master/src/dal_select2_queryset_sequence/fields.py#L24
https://github.com/yourlabs/django-autocomplete-light/blob/master/test_project/select2_generic_foreign_key/urls.py#L20

if you follow this lead you can acheive dry

@mpibpc-mroose

In 3.3.0-rc* there is a results in Select2ListView which you can override without much boilerplate (thx to @eayin2). If you want to add your DictView, a PR would be welcome.

To resolve this issue, should I create a new field/widget or refactor the existing ones?
I am not a python expert, my solution may not be idyllic.

I resolve the problem just create own class and override get method:

My List:
[('group', ('id', 'value'))]

class Select2GroupListView(autocomplete.Select2GroupListView):
    def get(self, request, *args, **kwargs):
        """"Return option list with children(s) json response."""
        results_dict = {}
        results = self.get_list()

        if results:
            flat_results = [(group, items) for entry in results
                            for group, items in self.get_item_as_group(entry)]

            if self.q:
                q = self.q.lower()
                flat_results = [(g, x) for g, x in flat_results
                                if q in x.lower()]
            for group, value in flat_results:
                results_dict.setdefault(group, [])
                results_dict[group].append(value)

        return http.HttpResponse(json.dumps({
            "results":
                [{"id": x, "text": y} for x, y in results_dict.pop(None, [])] +
                [{"id": g, "text": g, "children": [{"id": x, "text": y}
                                                   for x, y in l]}
                 for g, l in six.iteritems(results_dict)]
        }))

My solution to work with same choices that I put into model field choices attribute.

class Select2TuplesListView(autocomplete.Select2ListView):
    def autocomplete_results(self, results):
        filtered_results = []
        for current_tuple in results:
            name = current_tuple[1]
            print(name.lower())
            if self.q.lower() in name.lower():
                filtered_results.append(current_tuple)

        return filtered_results

    def results(self, results):
        """Return the result dictionary."""
        return [dict(id=x[0], text=x[1]) for x in results]

Usage example:

class CityCountryAutocomplete(Select2TuplesListView):
    def get_list(self):
        return services.get_geoip_cities_choices()  # returns list of tuples: [(1, 'a'), (2, 'b') ... ]
Was this page helpful?
0 / 5 - 0 ratings