From 8c4c07b5d0f56c2f9359923606305141cf9be99c Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Mon, 22 Jan 2007 06:48:10 +0000 Subject: [PATCH] newforms-admin: Added a custom formfield hook for the admin forms. The first customization is that ManyToManyFields with 'filter_interface' set use a special widget, FilteredSelectMultiple. This removes the need for the old filter_interface_script_maybe admin template tag. git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@4391 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/contrib/admin/options.py | 18 +++++++++++-- .../admin/templatetags/admin_modify.py | 10 ------- django/contrib/admin/widgets.py | 27 +++++++++++++++++++ 3 files changed, 43 insertions(+), 12 deletions(-) create mode 100644 django/contrib/admin/widgets.py diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 389a73fa93..e4fbf0005d 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -1,5 +1,6 @@ from django import oldforms, template from django import newforms as forms +from django.contrib.admin import widgets from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.db import models from django.http import Http404, HttpResponse, HttpResponseRedirect @@ -195,6 +196,19 @@ class ModelAdmin(object): for fs in self.fieldsets(request): yield fs + def formfield_for_dbfield(self, db_field, **kwargs): + """ + Hook for specifying the form Field instance for a given database Field + instance. + + If kwargs are given, they're passed to the form Field's constructor. + """ + # For filter_interface ManyToManyFields, use a special Widget. + if isinstance(db_field, models.ManyToManyField) and db_field.rel.filter_interface: + widget = widgets.FilteredSelectMultiple(db_field.verbose_name, db_field.rel.filter_interface-1) + return db_field.formfield(widget=widget) + return db_field.formfield(**kwargs) + def has_add_permission(self, request): "Returns True if the given request has permission to add an object." opts = self.opts @@ -238,7 +252,7 @@ class ModelAdmin(object): # Object list will give 'Permission Denied', so go back to admin home post_url = '../../../' - ModelForm = forms.form_for_model(model) + ModelForm = forms.form_for_model(model, formfield_callback=self.formfield_for_dbfield) if request.POST: new_data = request.POST.copy() @@ -303,7 +317,7 @@ class ModelAdmin(object): except model.DoesNotExist: raise Http404('%s object with primary key %r does not exist' % (model_name, escape(object_id))) - ModelForm = forms.form_for_instance(obj) + ModelForm = forms.form_for_instance(obj, formfield_callback=self.formfield_for_dbfield) if request.POST: new_data = request.POST.copy() diff --git a/django/contrib/admin/templatetags/admin_modify.py b/django/contrib/admin/templatetags/admin_modify.py index 7e9eb41f59..ab700d369d 100644 --- a/django/contrib/admin/templatetags/admin_modify.py +++ b/django/contrib/admin/templatetags/admin_modify.py @@ -160,16 +160,6 @@ def auto_populated_field_script(auto_pop_fields, change = False): return ''.join(t) auto_populated_field_script = register.simple_tag(auto_populated_field_script) -def filter_interface_script_maybe(bound_field): - f = bound_field.field - if f.rel and isinstance(f.rel, models.ManyToManyRel) and f.rel.filter_interface: - return '\n' % ( - f.name, f.verbose_name.replace('"', '\\"'), f.rel.filter_interface-1, settings.ADMIN_MEDIA_PREFIX) - else: - return '' -filter_interface_script_maybe = register.simple_tag(filter_interface_script_maybe) - def field_widget(parser, token): bits = token.contents.split() if len(bits) != 2: diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py new file mode 100644 index 0000000000..96346011ce --- /dev/null +++ b/django/contrib/admin/widgets.py @@ -0,0 +1,27 @@ +""" +Form Widget classes specific to the Django admin site. +""" + +from django import newforms as forms + +class FilteredSelectMultiple(forms.SelectMultiple): + """ + A SelectMultiple with a JavaScript filter interface. + + Note that the resulting JavaScript assumes that the SelectFilter2.js + library and its dependencies have been loaded in the HTML page. + """ + def __init__(self, verbose_name, is_stacked, attrs=None, choices=()): + self.verbose_name = verbose_name + self.is_stacked = is_stacked + super(FilteredSelectMultiple, self).__init__(attrs, choices) + + def render(self, name, value, attrs=None, choices=()): + from django.conf import settings + output = [super(FilteredSelectMultiple, self).render(name, value, attrs, choices)] + output.append('\n' % \ + (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX)) + return ''.join(output)