text: import json
  
  from django.http import HttpResponse
  from django.views.generic import View
  from django.core.exceptions import PermissionDenied
  from django.http import Http404
  
  from .util import get_field, is_valid_id
  
  NO_ERR_RESP = 'nil'
  """
  Equals to 'nil' constant.
  
  Use this in :py:meth:`.Select2View.get_results` to mean no error, instead of hardcoding 'nil' value.
  """
  
  class JSONResponseMixin(object):
      """
      A mixin that can be used to render a JSON response.
      """
      response_class = HttpResponse
  
      def render_to_response(self, context, **response_kwargs):
          """
          Returns a JSON response, transforming 'context' to make the payload.
          """
          response_kwargs['content_type'] = 'application/json'
          return self.response_class(
              self.convert_context_to_json(context),
              **response_kwargs
          )
  
      def convert_context_to_json(self, context):
          "Convert the context dictionary into a JSON object"
          return json.dumps(context)
  
  class Select2View(JSONResponseMixin, View):
      """
      Base view which is designed to respond with JSON to Ajax queries from heavy widgets/fields.
  
      Although the widgets won't enforce the type of data_view it gets, but it is recommended to
      sub-class this view instead of creating a Django view from scratch.
  
      .. note:: Only `GET <http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.3>`_ Http requests are supported.
      """
  
      def dispatch(self, request, *args, **kwargs):
          try:
              self.check_all_permissions(request, *args, **kwargs)
          except Exception, e:
              return self.respond_with_exception(e)
          return super(Select2View, self).dispatch(request, *args, **kwargs)
  
      def get(self, request, *args, **kwargs):
          if request.method == 'GET':
              term = request.GET.get('term', None)
              if term is None:
                  return self.render_to_response(self._results_to_context(('missing term', False, [], )))
              if not term:
                  return self.render_to_response(self._results_to_context((NO_ERR_RESP, False, [], )))
  
              try:
                  page = int(request.GET.get('page', None))
                  if page <= 0:
                      page = -1
              except ValueError:
                  page = -1
              if page == -1:
                  return self.render_to_response(self._results_to_context(('bad page no.', False, [], )))
              context = request.GET.get('context', None)
          else:
              return self.render_to_response(self._results_to_context(('not a get request', False, [], )))
  
          return self.render_to_response(
              self._results_to_context(
                  self.get_results(request, term, page, context)
                  )
              )
  
      def respond_with_exception(self, e):
          """
          :param e: Exception object.
          :type e: Exception
          :return: Response with status code of 404 if e is ``Http404`` object,
              else 400.
          :rtype: HttpResponse
          """
          if isinstance(e, Http404):
              status = 404
          else:
              status = getattr(e, 'status_code', 400)
          return self.render_to_response(
              self._results_to_context((str(e), False, [],)),
              status=status
              )
  
      def _results_to_context(self, output):
          err, has_more, results = output
          res = []
          if err == NO_ERR_RESP:
              for result in results:
                  id_, text = result[:2]
                  if len(result)>2:
                      extra_data = result[2]
                  else:
                      extra_data = {}
                  res.append(dict(id=id_, text=text, **extra_data))
          return {
              'err': err,
              'more': has_more,
              'results': res,
          }
  
      def check_all_permissions(self, request, *args, **kwargs):
          """
          Sub-classes can use this to raise exception on permission check failures,
          or these checks can be placed in ``urls.py``, e.g. ``login_required(SelectClass.as_view())``.
  
          :param request: The Ajax request object.
          :type request: :py:class:`django.http.HttpRequest`
  
          :param args: The ``*args`` passed to :py:meth:`django.views.generic.View.dispatch`.
          :param kwargs: The ``**kwargs`` passed to :py:meth:`django.views.generic.View.dispatch`.
  
          .. warning:: Sub-classes should override this. You really do not want random people making
              Http reqeusts to your server, be able to get access to sensitive information.
          """
          pass
  
      def get_results(self, request, term, page, context):
          """
          Returns the result for the given search ``term``.
  
          :param request: The Ajax request object.
          :type request: :py:class:`django.http.HttpRequest`
  
          :param term: The search term.
          :type term: :py:obj:`str`
  
          :param page: The page number. If in your last response you had signalled that there are more results,
              then when user scrolls more a new Ajax request would be sent for the same term but with next page
              number. (Page number starts at 1)
          :type page: :py:obj:`int`
  
          :param context: Can be anything which persists across the lifecycle of queries for the same search term.
              It is reset to ``None`` when the term changes.
  
              .. note:: Currently this is not used by ``heavy_data.js``.
          :type context: :py:obj:`str` or None
  
          Expected output is of the form::
  
              (err, has_more, [results])
  
          Where ``results = [(id1, text1), (id2, text2), ...]``
  
          For example::
  
              ('nil', False,
                  [
                  (1, 'Value label1'),
                  (20, 'Value label2'),
                  ])
  
          When everything is fine then the `err` must be 'nil'.
          `has_more` should be true if there are more rows.
          """
          raise NotImplementedError
  
  
  class AutoResponseView(Select2View):
      """
      A central view meant to respond to Ajax queries for all Heavy widgets/fields.
      Although it is not mandatory to use, but is immensely helpful.
  
      .. tip:: Fields which want to use this view must sub-class :py:class:`~.widgets.AutoViewFieldMixin`.
      """
      def check_all_permissions(self, request, *args, **kwargs):
          id_ = request.GET.get('field_id', None)
          if id_ is None or not is_valid_id(id_):
              raise Http404('field_id not found or is invalid')
          field = get_field(id_)
          if field is None:
              raise Http404('field_id not found')
  
          if not field.security_check(request, *args, **kwargs):
              raise PermissionDenied('permission denied')
  
          request.__django_select2_local = field
  
      def get_results(self, request, term, page, context):
          field = request.__django_select2_local
          del request.__django_select2_local
          return field.get_results(request, term, page, context)
  
  
  