This snippet allows you to use YUI's autocomplete widget in a easy way.
-
Download YUI (http://developer.yahoo.com/yui/) library and put it into MEDIA folder (in my case I put YUI/build/ directory as base/yui/ in my MEDIA folder)
-
Create lookup view for your autocomplete field. See 'test_ajax_ac' function to see how this lookup view may be built. You have to define JsonResponse somewhere in your files. JsonResponse is taken from: http://www.djangosnippets.org/snippets/154/
-
Define url for newly created view in urls.py (in usual way)
-
Include necessary .js and .css files in your page (see example in test_ajax.html)
-
Assign widget to a field - see form's init at UserForm in the example. Additional (optional) parameters are: format_result_fname (name of javascript function for formatting results - see YUI docs for examples)), item_select_handler_fname (name of javascript function for handling item select event (see YUI docs)).
When using YUI take care about proper skin - you'll possibly need to define wrapper like:
<div class="yui-skin-sam">....</div>
around your html code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | #----------------------- widgets.py------------------------
# -*- coding: utf-8 -*-
#
# In order to use this widget you need:
# 1. download YUI library and put it in
# your MEDIA folder (http://developer.yahoo.com/yui/)
# 2. Include necessary js and css imports at your page
# Check for necessary imports at 'YUI autocomplete' page
# My imports are visible at test_ajax.html
# 3. Assign a widget to field (with schema and lookup_url parameters)
# 4. Define view to do a data lookup for ajax queries
#
from django import newforms as forms
from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode
#AUTOCOMPLETE
AC_SNIPPET = """
<div class="ac_container">
<input %s />
<div id="%s_container" class="yui-skin-sam"></div>
<script type="text/javascript">
// An XHR DataSource
var acServer_%s = "%s";
var acSchema_%s = %s;
var acDataSource_%s = new YAHOO.widget.DS_XHR(acServer_%s, acSchema_%s);
var acAutoComp_%s = new YAHOO.widget.AutoComplete("%s","%s_container", acDataSource_%s);
acAutoComp_%s.useIFrame = true;
acAutoComp_%s.animSpeed = 0;
%s
%s
</script>
</div>
"""
def_format_result = 'acAutoComp_%s.formatResult = %s;'
def_item_select_handler = 'acAutoComp_%s.itemSelectEvent.subscribe(%s);'
class AutoCompleteWidget(forms.widgets.TextInput):
""" widget autocomplete for text fields
"""
def __init__(self,
schema=None,
lookup_url=None,
format_result_fname='',
item_select_handler_fname='',
*args, **kw):
super(AutoCompleteWidget, self).__init__(*args, **kw)
# YUI schema
self.schema = schema
# url for YUI XHR Datasource
self.lookup_url = lookup_url
# optional name of javascript function that formats results (YUI)
self.format_result_fname = format_result_fname
# optional name of javascript function that handles item select event (YUI)
self.item_select_handler_fname = item_select_handler_fname
def render(self, name, value, attrs=None):
html_id = attrs.get('id', name)
# url for YUI XHR Datasource
lookup_url = self.lookup_url
# YUI schema
schema = self.schema
# optional name of javascript function that handles item select event (YUI)
item_select_handler_fname = getattr(self, 'item_select_handler_fname', '')
# optional name of javascript function that formats results (YUI)
format_result_fname = getattr(self, 'format_result_fname', '')
if value is None: value = ''
final_attrs = self.build_attrs(attrs, type=self.input_type, name=name)
if value != '': final_attrs['value'] = force_unicode(value) # Only add the 'value' attribute if a value is non-empty.
final_attrs['class'] = 'autocomplete_widget'
fr = '' # format result
sh = '' # select handler
if self.format_result_fname:
fr = def_format_result % (html_id, self.format_result_fname)
if self.item_select_handler_fname:
sh = def_item_select_handler % (html_id,
self.item_select_handler_fname)
return mark_safe(AC_SNIPPET % (forms.util.flatatt(final_attrs), html_id, html_id,
lookup_url,html_id, schema, html_id, html_id,
html_id, html_id, html_id, html_id,
html_id,html_id, html_id, fr, sh))
#/AUTOCOMPLETE
#/----------------------- widgets.py------------------------
#
#EXAMPLE APPLICATION: ---------------------------------------
#
# code below is a listing of files from example application
# that uses AutocompleteWidget, you don't have to create these
# files! Only thing you need to put into your application
# is code from above: widgets.py
#----------------------- test_ajax.html -------------------
<html>
<head>
<!-- yui -->
<link rel="stylesheet" type="text/css" href="{{ MEDIA_URL }}base/js/yui/assets/skins/sam/autocomplete.css" />
<script type="text/javascript" src="{{ MEDIA_URL }}base/js/yui/utilities/utilities.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}base/js/yui/autocomplete/autocomplete-min.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}base/js/yui/datasource/datasource-beta-min.js"></script>
<!-- /yui-->
</head>
<body>
<div class="yui-skin-sam">
<form>
{{ user_form.as_p }}
</form>
</div>
</body>
</html>
#/----------------------- test_ajax.html -------------------
#----------------------- views.py------------------------
# -*- coding: utf-8 -*-
from <SOMEWHERE: http://www.djangosnippets.org/snippets/154/> import JsonResponse
from django.contrib.auth.models import User
from django.template import RequestContext
import django.db.models
from django.shortcuts import render_to_response
from django import newforms as forms
from widgets import AutoCompleteWidget
def test_ajax_ac(request):
""" returns data displayed at autocomplete list - this function is accessed by AJAX calls
"""
limit = 10
query = request.GET.get('query', None)
qargs = []
# it is up to you how query looks
if query:
qargs = [django.db.models.Q(first_name__startswith=query) | \
django.db.models.Q(last_name__startswith=query) | \
django.db.models.Q(email__startswith=query)]
users = User.objects.filter(django.db.models.Q(*qargs)).order_by('first_name')[:limit]
results = []
for user in users:
results.append({'id':user.pk,
'name':user.get_full_name(),
'email':user.email})
ret_dict = {'resultset':{'totalResultsReturned':len(results),
'results':results}}
return JsonResponse(ret_dict)
class UserForm(forms.Form):
username = forms.CharField(max_length=100)
def __init__(self, *args, **kwargs):
super(UserForm, self).__init__(*args, **kwargs)
n_lookup_url = reverse('test_ajax_ac')
n_schema = '["resultset.results", "name", "email"]'
self.fields['username'].widget = \
AutoCompleteWidget(lookup_url = n_lookup_url,
schema = n_schema)
def test_ajax(request):
""" Displays user form
"""
user_form = UserForm()
return render_to_response('test_ajax.html',
{'user_form':user_form},
context_instance=RequestContext(request))
#/----------------------- views.py------------------------
#------------------------ urls.py-------------------------
from django.conf.urls.defaults import *
from django.conf import settings
urlpatterns = patterns('views',
url(r'^test_ajax/$', 'test_ajax', name='test_ajax'),
url(r'^test_ajax_ac/$', 'test_ajax_ac', name='test_ajax_ac'),
)
#/------------------------ urls.py-------------------------
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 9 months ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 9 months, 1 week ago
- Serializer factory with Django Rest Framework by julio 1 year, 4 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 4 months ago
- Help text hyperlinks by sa2812 1 year, 5 months ago
Comments
Thanx for the snippet. The .js imports needed updating but other than that it works fine.
One small note. It would really be better to used named parameters on the
AC_SNIPPET
instead of repeatinghtml_id
a billion times :p#
Please login first before commenting.