### Navigation

- index
- modules
- toc
- jmb.core 0.8.6 documentation »
- Module code »

# Source code for jmb.core.utils.autocomplete

    # coding: utf-8

    """

    ===============
    Autocompletion
    ===============

    Autocompletion is obtained throught autocomplete_light_ package.

    .. _dynamic-autocompletion:

    Dynamic Autocompletion
    =======================

    We attach to the change of the selection of the main autocomplete
    to add data to the dependent autocomplete so that it will be used
    when issuing the request to the server.

    We also take care of cleaning up stale data of the previous select from
    the choices box and make sure this cascade correctly in case of
    several autocompletes channed toghether.

    This module provides :class:`DynamicAutocompleteModelBase` a class that
    inherits from ``autocomplete_light.AutocompleteModelBase``.

    You can define a dictionary called ``filters`` whose keys are queryset filter
    keywords and whose values are dom id. The js widget will retrieve the values
    of the ids and send them along with the string used in the autocompletion
    Foreign Key Examples::

        from jmb.core.utils.autocomplete import DynamicAutocompleteModelBase

        class MyAutocomplete(DynamicAutocompleteModelBase):
            dependency_map = {
                 'organization_id' : '#id_organization',
                 'project_id'  : '#id_project',
            }

    M2M examples::

        from jmb.core.utils.autocomplete import DynamicAutocompleteModelBase

        class MyAutocomplete(DynamicAutocompleteModelBase):
            dependency_map = {
                 'organizations' : '#id_organization',
                 'projects'  : '#id_project',
            }

    In TabularInline case, StackedInline and similar, you can't set the id of field, but use this syntax::

        dependency_map = {
             'corporate_id' : '#id_car_details-x-corporate',
             'brand_id' : '#id_car_details-x-brand',
             'model_id' : '#id_car_details-x-model'
        }

    In this situation the widget will call the url::

        /ticket/autocomplete/MyAutocomplete/?q=san&organization_id=1530&project_id=10

    that will be handled automatically by ``choices_for_request``

    To have the complete list of all choice set minimum_characters to 0 in autocomplete_js_attributes
    dictionary, example::

        class CustomerContactAutocomplete(ContactAutocomplete):
            model = Contact
            dependency_map = {
                'organization_id' : '#id_organization',
            }
            autocomplete_js_attributes = {
                'minimum_characters': 0,
            }

    To add an object in autocomplete with plus button on the right, add
    ``add_another_url_name`` value in autocomplete registry, example::

        autocomplete_light.register(RouteAutocomplete, add_another_url_name='admin:event_route_add')

    The object saved, will be selected automatically in the select
    At the moment this feature only works with single model choice field.

    .. autoclass:: DynamicAutocompleteModelBase
       :members: filters, choices_for_request, get_filters

    .. _autocomplete_light: http://django-autocomplete-light.readthedocs.org/en/latest/

    """
    import json
    try:
        from autocomplete_light.autocomplete import shortcuts as al
    except ImportError:
        import autocomplete_light as al
    import autocomplete_light

    class DynamicAutocompleteModelBase(al.AutocompleteModelBase):
        #: a dict. *Keys* must be keywords to filter a queryset, e.g.: organization_id,
        #: organization__address__country_id, and the *values* must be id in the html page
        #: whose value will be retrieved by javascript and sent along (e.g.: #organization_id)
        dependency_map = {
            # 'organization_id' : '#id_organization',
        }

        def __init__(self, *args, **kw):
            # backward compatibility
            if hasattr(self, 'filters'):
                self.dependency_map.update(getattr(self, 'filters', {}))

            json_data = json.dumps(self.dependency_map)
            if getattr(autocomplete_light, '__version__', (1,)) < (2, 0):
                self.autocomplete_js_attributes['data-autocomplete-dependency-map'] = json_data
            else:
                if not hasattr(self, 'attrs'):
                    self.attrs = {}
                self.attrs['data-autocomplete-dependency-map'] = json_data
            super(DynamicAutocompleteModelBase, self).__init__(*args, **kw)

        def choices_for_request(self):
            """
            Return all choices taking into account all dynamic filters
            you may need to customize this
            """
            self.choices = self.model.objects.all()
            filters = self.get_filters()
            self.choices = self.choices.filter(**filters)

            return super(DynamicAutocompleteModelBase, self).choices_for_request()

        def get_filters(self):
            """
            Return  a dictionary suitable to filter self.choices using self.filters
            """
            filters = {}
            for key in self.dependency_map:
                value = self.request.GET.get(key, '')
                if value:
                    filters[key] = value
            return filters

### Navigation

- index
- modules
- toc
- jmb.core 0.8.6 documentation »
- Module code »