5 --------------------------------------
7 Lookups define the corresponding ajax views used by the auto-completion
8 fields and widgets. They take in the current request and return the JSON
9 needed by the jQuery auto-complete plugin.
13 --------------------------------------
15 django-selectable uses a registration pattern similar to the Django admin.
16 Lookups should be defined in a `lookups.py` in your application's module. Once defined
17 you must register in with django-selectable. All lookups must extend from
18 ``selectable.base.LookupBase`` which defines the API for every lookup.
20 .. code-block:: python
22 from selectable.base import LookupBase
23 from selectable.registry import registry
25 class MyLookup(LookupBase):
26 def get_query(self, request, term):
28 return [x for x in data if x.startswith(term)]
30 registry.register(MyLookup)
34 --------------------------------------
36 .. py:method:: LookupBase.get_query(request, term)
38 This is the main method which takes the current request
39 from the user and returns the data which matches their search.
41 :param request: The current request object.
42 :param term: The search term from the widget input.
43 :return: An iterable set of data of items matching the search term.
45 .. _lookup-get-item-label:
47 .. py:method:: LookupBase.get_item_label(item)
49 This is first of three formatting methods. The label is shown in the
50 drop down menu of search results. This defaults to ``item.__unicode__``.
52 :param item: An item from the search results.
53 :return: A string representation of the item to be shown in the search results.
54 The label can include HTML. For changing the label format on the client side
55 see :ref:`Advanced Label Formats <advanced-label-formats>`.
58 .. py:method:: LookupBase.get_item_id(item)
60 This is second of three formatting methods. The id is the value that will eventually
61 be returned by the field/widget. This defaults to ``item.__unicode__``.
63 :param item: An item from the search results.
64 :return: A string representation of the item to be returned by the field/widget.
66 .. py:method:: LookupBase.get_item_value(item)
68 This is last of three formatting methods. The value is shown in the
69 input once the item has been selected. This defaults to ``item.__unicode__``.
71 :param item: An item from the search results.
72 :return: A string representation of the item to be shown in the input.
74 .. py:method:: LookupBase.get_item(value)
76 ``get_item`` is the reverse of ``get_item_id``. This should take the value
77 from the form initial values and return the current item. This defaults
78 to simply return the value.
80 :param value: Value from the form inital value.
81 :return: The item corresponding to the initial value.
83 .. py:method:: LookupBase.create_item(value)
85 If you plan to use a lookup with a field or widget which allows the user
86 to input new values then you must define what it means to create a new item
87 for your lookup. By default this raises a ``NotImplemented`` error.
89 :param value: The user given value.
90 :return: The new item created from the item.
92 .. _lookup-format-item:
94 .. py:method:: LookupBase.format_item(item)
96 By default ``format_item`` creates a dictionary with the three keys used by
97 the UI plugin: id, value, label. These are generated from the calls to
98 ``get_item_id``, ``get_item_value`` and ``get_item_label``. If you want to
99 add additional keys you should add them here.
101 The results of ``get_item_label`` is conditionally escaped to prevent
102 Cross Site Scripting (XSS) similar to the templating language.
103 If you know that the content is safe and you want to use these methods
104 to include HTML should mark the content as safe with ``django.utils.safestring.mark_safe``
105 inside the ``get_item_label`` method.
107 ``get_item_id`` and ``get_item_value`` are not escapted by default. These are
108 not a XSS vector with the built-in JS. If you are doing additional formating using
109 these values you should be conscience of this fake and be sure to escape these
112 :param item: An item from the search results.
113 :return: A dictionary of information for this item to be sent back to the client.
115 There are also some additional methods that you could want to use/override. These
116 are for more advanced use cases such as using the lookups with JS libraries other
117 than jQuery UI. Most users will not need to override these methods.
119 .. _lookup-format-results:
121 .. py:method:: LookupBase.format_results(self, raw_data, options)
123 Returns a python structure that later gets serialized. This makes a call to
124 :ref:`paginate_results<lookup-paginate-results>` prior to calling
125 :ref:`format_item<lookup-format-item>` on each item in the current page.
127 :param raw_data: The set of all matched results.
128 :param options: Dictionary of ``cleaned_data`` from the lookup form class.
129 :return: A dictionary with two keys ``meta`` and ``data``.
130 The value of ``data`` is an iterable extracted from page_data.
131 The value of ``meta`` is a dictionary. This is a copy of options with one additional element
132 ``more`` which is a translatable "Show more" string
133 (useful for indicating more results on the javascript side).
135 .. _lookup-paginate-results:
137 .. py:method:: LookupBase.paginate_results(results, options)
139 If :ref:`SELECTABLE_MAX_LIMIT` is defined or ``limit`` is passed in request.GET
140 then ``paginate_results`` will return the current page using Django's
141 built in pagination. See the Django docs on
142 `pagination <https://docs.djangoproject.com/en/stable/topics/pagination/>`_
145 :param results: The set of all matched results.
146 :param options: Dictionary of ``cleaned_data`` from the lookup form class.
147 :return: The current `Page object <https://docs.djangoproject.com/en/stable/topics/pagination/#page-objects>`_
153 Lookups Based on Models
154 --------------------------------------
156 Perhaps the most common use case is to define a lookup based on a given Django model.
157 For this you can extend ``selectable.base.ModelLookup``. To extend ``ModelLookup`` you
158 should set two class attributes: ``model`` and ``search_fields``.
160 .. code-block:: python
162 from __future__ import unicode_literals
164 from selectable.base import ModelLookup
165 from selectable.registry import registry
167 from .models import Fruit
170 class FruitLookup(ModelLookup):
172 search_fields = ('name__icontains', )
174 registry.register(FruitLookup)
176 The syntax for ``search_fields`` is the same as the Django
177 `field lookup syntax <http://docs.djangoproject.com/en/stable/ref/models/querysets/#field-lookups>`_.
178 Each of these lookups are combined as OR so any one of them matching will return a
179 result. You may optionally define a third class attribute ``filters`` which is a dictionary of
180 filters to be applied to the model queryset. The keys should be a string defining a field lookup
181 and the value should be the value for the field lookup. Filters on the other hand are
186 --------------------------------------
188 Below is a larger model lookup example using multiple search fields, filters
189 and display options for the `auth.User <https://docs.djangoproject.com/en/stable/topics/auth/#users>`_
192 .. code-block:: python
194 from django.contrib.auth.models import User
195 from selectable.base import ModelLookup
196 from selectable.registry import registry
199 class UserLookup(ModelLookup):
202 'username__icontains',
203 'first_name__icontains',
204 'last_name__icontains',
206 filters = {'is_active': True, }
208 def get_item_value(self, item):
209 # Display for currently selected item
212 def get_item_label(self, item):
213 # Display for choice listings
214 return u"%s (%s)" % (item.username, item.get_full_name())
216 registry.register(UserLookup)
219 .. _lookup-decorators:
222 --------------------------------------
224 Registering lookups with django-selectable creates a small API for searching the
225 lookup data. While the amount of visible data is small there are times when you want
226 to restrict the set of requests which can view the data. For this purpose there are
227 lookup decorators. To use them you simply decorate your lookup class.
229 .. code-block:: python
231 from django.contrib.auth.models import User
232 from selectable.base import ModelLookup
233 from selectable.decorators import login_required
234 from selectable.registry import registry
238 class UserLookup(ModelLookup):
240 search_fields = ('username__icontains', )
241 filters = {'is_active': True, }
243 registry.register(UserLookup)
247 The class decorator syntax was introduced in Python 2.6. If you are using
248 django-selectable with Python 2.5 you can still make use of these decorators
249 by applying the without the decorator syntax.
251 .. code-block:: python
253 class UserLookup(ModelLookup):
255 search_fields = ('username__icontains', )
256 filters = {'is_active': True, }
258 UserLookup = login_required(UserLookup)
260 registry.register(UserLookup)
262 Below are the descriptions of the available lookup decorators.
266 ______________________________________
268 The django-selectable javascript will always request the lookup data via
269 XMLHttpRequest (AJAX) request. This decorator enforces that the lookup can only
270 be accessed in this way. If the request is not an AJAX request then it will return
271 a 400 Bad Request response.
275 ______________________________________
277 This decorator requires the user to be authenticated via ``request.user.is_authenticated``.
278 If the user is not authenticated this will return a 401 Unauthorized response.
279 ``request.user`` is set by the ``django.contrib.auth.middleware.AuthenticationMiddleware``
280 which is required for this decorator to work. This middleware is enabled by default.
282 staff_member_required
283 ______________________________________
285 This decorator builds from ``login_required`` and in addition requires that
286 ``request.user.is_staff`` is ``True``. If the user is not authenticatated this will
287 continue to return at 401 response. If the user is authenticated but not a staff member
288 then this will return a 403 Forbidden response.