Anonymous avatar Anonymous committed 6d038d6

Made autocomplete_fields a dict of dicts to allow further customization.

Comments (0)

Files changed (2)

django/contrib/admin/options.py

     models.FileField:       {'widget': widgets.AdminFileWidget},
 }
 
+AUTOCOMPLETE_FIELDS_DEFAULTS = dict(
+    limit = 5,
+    value = lambda o: unicode(o),
+    label = lambda o: unicode(o),
+)
+
 csrf_protect_m = method_decorator(csrf_protect)
 
 class BaseModelAdmin(object):
         overrides.update(self.formfield_overrides)
         self.formfield_overrides = overrides
 
+        def build_setting(value, field):
+            rel_model = getattr(self.model, field).field.rel.to
+            if value in rel_model._meta.get_all_field_names():
+                return lambda m: getattr(m, value)
+            return lambda m: value % vars(m)
+
+        autocomplete_fields = {}
+        for (field, values) in self.autocomplete_fields.items():
+            settings = autocomplete_fields[field] = AUTOCOMPLETE_FIELDS_DEFAULTS.copy()
+            settings.update(values)
+            for option in ('value', 'label'):
+                if isinstance(settings[option], (str, unicode)):
+                    settings[option] = build_setting(settings[option], field)
+
+        self.autocomplete_fields = autocomplete_fields
+
+
     def formfield_for_dbfield(self, db_field, **kwargs):
         """
         Hook for specifying the form Field instance for a given database Field
             # extra HTML -- the "add other" interface -- to the end of the
             # rendered output. formfield can be None if it came from a
             # OneToOneField with parent_link=True or a M2M intermediary.
-            if formfield and db_field.name not in self.raw_id_fields:
+            if (formfield and db_field.name not in self.raw_id_fields
+                and db_field.name not in self.autocomplete_fields):
                 related_modeladmin = self.admin_site._registry.get(
                                                             db_field.rel.to)
                 can_add_related = bool(related_modeladmin and
         if db_field.name in self.raw_id_fields:
             kwargs['widget'] = widgets.ForeignKeyRawIdWidget(db_field.rel, using=db)
         elif db_field.name in self.autocomplete_fields:
-            kwargs['widget'] = widgets.ForeignKeyAutocompleteWidget(db_field.rel, using=db)
+            kwargs['widget'] = widgets.ForeignKeyAutocompleteWidget(db_field.rel,
+                self.autocomplete_fields[db_field.name], using=db)
         elif db_field.name in self.radio_fields:
             kwargs['widget'] = widgets.AdminRadioSelect(attrs={
                 'class': get_ul_class(self.radio_fields[db_field.name]),
             kwargs['widget'] = widgets.ManyToManyRawIdWidget(db_field.rel, using=db)
             kwargs['help_text'] = ''
         elif db_field.name in self.autocomplete_fields:
-            kwargs['widget'] = widgets.ManyToManyAutocompleteWidget(db_field.rel, using=db)
+            kwargs['widget'] = widgets.ManyToManyAutocompleteWidget(db_field.rel,
+                self.autocomplete_fields[db_field.name], using=db)
             kwargs['help_text'] = ''
         elif db_field.name in (list(self.filter_vertical) + list(self.filter_horizontal)):
             kwargs['widget'] = widgets.FilteredSelectMultiple(db_field.verbose_name, (db_field.name in self.filter_vertical))
         if field not in self.autocomplete_fields or query is None:
             raise Http404
         
-        related = getattr(self.model, field)
-        rel_model = related.field.rel.to
+        rel_model = getattr(self.model, field).field.rel.to
+        # XXX are we considering limit_choices_to ?
         queryset = rel_model._default_manager.all()
-        search_fields = self.autocomplete_fields[field]
+        settings = self.autocomplete_fields[field]
         
         def construct_search(field_name):
             # use different lookup methods depending on the notation
         for bit in query.split():
             or_queries = [models.Q(**{construct_search(
                 smart_str(field_name)): bit})
-                    for field_name in search_fields]
+                    for field_name in settings['fields']]
 
             queryset = queryset.filter(reduce(operator.or_, or_queries))
         
-        data = [{"id": o.pk, "value": unicode(o)} for o in queryset]
+        data = []
+        for o in queryset[:settings['limit']]:
+            data.append(dict(
+                id = o.pk,
+                value = settings['value'](o),
+                label = settings['label'](o),
+            ))
         
         return HttpResponse(simplejson.dumps(data))
     

django/contrib/admin/widgets.py

             settings.ADMIN_MEDIA_PREFIX + 'js/admin/autocomplete.js',
         )
 
-    def __init__(self, rel, attrs=None, using=None):
+    def __init__(self, rel, settings, attrs=None, using=None):
         self.rel = rel
+        self.settings = settings
         self.db = using
         super(ForeignKeyAutocompleteWidget, self).__init__(attrs)
 
         key = self.rel.get_related_field().name
         try:
             obj = self.rel.to._default_manager.using(self.db).get(**{key: value})
-            return truncate_words(obj, 14)
+            return self.settings['value'](obj)
         # XXX this shouldn't happen.
         except self.rel.to.DoesNotExist:
             return value
         output = [super(ManyToManyAutocompleteWidget, self).render(name, value, attrs)]
         output.append('<ul class="ui-autocomplete-values">')
         for o in objs:
-            output.append('<li>%s</li>' % unicode(o))
+            output.append('<li>%s</li>' % self.settings['label'](o))
         output.append('</ul>')
         return mark_safe(u''.join(output))
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.