blithewu 发表于 2013-1-29 12:07:47

使用jquery的AutocompleteWidget

from django.core.urlresolvers import reverse, NoReverseMatchfrom django.newforms import HiddenInput, TextInputfrom django.utils import simplejsonfrom django.utils.safestring import mark_safeclass AutocompleteWidget(TextInput):    """    Autocomplete widget to use with jquery-autocomplete plugin.    Widget can use for static and dynamic (AJAX-liked) data. Also    you can relate some fields and it's values'll posted to autocomplete    view.    Widget support all jquery-autocomplete options that dumped to JavaScript    via django.utils.simplejson.    **Note** You must init one of ``choices`` or ``choices_url`` attribute.    Else widget raises TypeError when rendering.    """    def __init__(self, attrs=None, choices=None, choices_url=None, options=None, related_fields=None):      """      Optional arguments:      -------------------            * ``choices`` - Static autocomplete choices (similar to choices            used in Select widget).            * ``choices_url`` - Path to autocomplete view or autocomplete            url name.            * ``options`` - jQuery autocomplete plugin options. Auto dumped            to JavaScript via SimpleJSON            * ``related_fields`` - Fields that relates to current (value            of this field will sended to autocomplete view via POST)      """      self.attrs = attrs or {}      self.choice, self.choices, self.choices_url = None, choices, choices_url      self.options = options or {}      if related_fields:            extra = {}            if isinstance(related_fields, str):                related_fields = list(related_fields)            for field in related_fields:                extra = "%s_value" % field            self.extra = extra      else:            self.extra = {}    def render(self, name, value=None, attrs=None):      if not self.choices and not self.choices_url:            raise TypeError('One of "choices" or "choices_url" keyword argument must be supplied obligatory.')      if self.choices and self.choices_url:            raise TypeError('Only one of "choices" or "choices_url" keyword argument can be supplied.')      choices = ''      if self.choices:            self.set_current_choice(value)            choices = simplejson.dumps(, ensure_ascii=False)            html_code = HiddenInput().render(name, value=value)            name += '_autocomplete'      else:            html_code = ''      if self.choices_url:            try:                choices = simplejson.dumps(reverse(str(self.choices_url)))            except NoReverseMatch:                choices = simplejson.dumps(self.choices_url)      if self.options or self.extra:            if 'extraParams' in self.options:                self.options['extraParams'].update(self.extra)            else:                self.options['extraParams'] = self.extra            options = ', ' + simplejson.dumps(self.options, indent=4, sort_keys=True)            extra = []            for k, v in self.extra.items():                options = options.replace(simplejson.dumps(v), v)                extra.append(u"function %s() { return $('#id_%s').val(); }\n" % (v, k))            extra = u''.join(extra)      else:            extra, options = '', ''      final_attrs = self.build_attrs(attrs)      html_code += super(AutocompleteWidget, self).render(name, self.choice or value, attrs)      html_code += u"""<script type="text/javascript"><!--    %s$('#%s').autocomplete(%s%s);--></script>""" % (extra, final_attrs['id'], choices, options)      return mark_safe(html_code)    def set_current_choice(self, data):      if not self.choices:            raise ValueError('"choices" attribute was not defined yet.')      for k, v in self.choices:            if k == data:                self.choice = v                break    def value_from_datadict(self, data, files, name):      if not self.choices:            return super(AutocompleteWidget, self).value_from_datadict(data, files, name)      autocomplete_name = name + '_autocomplete'      if not autocomplete_name in data:            self.set_current_choice(data)            return data      for k, v in self.choices:            if v == data:                self.set_current_choice(k)                return k
<strong>forms.py</strong>from django import newforms as formsfrom django.utils.translation import ugettext as _from myproject.widgets import AutocompleteWidgetSPORTS_CHOICES = (    ('basketball', _('Basketball')),    ('football', _('Football')),    ('hockey', _('Hockey')),)class SampleForm(forms.Form):    name = forms.CharField(label=_('Name'))    country = forms.CharField(label=_('Country'),      widget=AutocompleteWidget(choices_url='autocomplete_countries', related_fields=('city',)))    city = forms.CharField(label=_('City),      widget=AutocompleteWidget(choices_url='autocomplete_cities', related_fields=('country',)))    sports = forms.ChoiceField(label=_('Sports'), choices=SPORTS_CHOICES,      widget=AutocompleteWidget(options={'minChars': 0, 'autoFill': True, 'mustMatch': True}))<strong>urls.py</strong>from django.conf.urls.defaults import *urlpatterns = patterns('',    url('/path/to/cities/autocomplete/', 'views.autocomplete_cities', name='autocomplete_cities'),    url('/path/to/countries/autocomplete/', 'views.autocomplete_countries', name='autocomplete_countries'),)<strong>views.py</strong>from myproject.models import Citydef autocomplete_cities(request):    def results_to_string(results):      if results:            for r in results:                yield '%s|%s\n' % (r.name, r.pk)    city = request.REQUEST.get('q', None)    country = request.REQUEST.get('country', None)    if city:      cities = City.objects.filter(city__istartswith=city)    else:      cities = City.objects.all()    if country:      cities = cities.filter(country__name=country)    cities = cities[:int(request.REQUEST.get('limit', 15))]    return results_to_string(cities, mimetype='text/plain')
http://djangonaut.blogspot.com/2008/05/jquery-autocompletewidget-django.html
页: [1]
查看完整版本: 使用jquery的AutocompleteWidget