1
0
mirror of https://github.com/django/django.git synced 2025-07-05 18:29:11 +00:00

newforms-admin: Made the first step in converting add and change forms to use newforms. Got rid of some overengineered admin template tags along the way.

git-svn-id: http://code.djangoproject.com/svn/django/branches/newforms-admin@4372 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Adrian Holovaty 2007-01-20 21:16:31 +00:00
parent 23b628d731
commit 9c5e28e1e8
4 changed files with 121 additions and 126 deletions

View File

@ -1,4 +1,5 @@
from django import oldforms, template from django import oldforms, template
from django import newforms as forms
from django.core.exceptions import ImproperlyConfigured, PermissionDenied from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.db import models from django.db import models
from django.http import Http404, HttpResponse, HttpResponseRedirect from django.http import Http404, HttpResponse, HttpResponseRedirect
@ -67,13 +68,63 @@ class AdminFieldLine(object):
def __len__(self): def __len__(self):
return len(self.fields) return len(self.fields)
# New implementation of Fieldset class AdminForm(object):
def __init__(self, form, fieldsets):
self.form, self.fieldsets = form, fieldsets
def __iter__(self):
for fieldset in self.fieldsets:
yield BoundFieldset(self.form, fieldset)
class Fieldset(object): class Fieldset(object):
def __init__(self, name=None, fields=(), classes=(), description=None): def __init__(self, name=None, fields=(), classes=(), description=None):
self.name, self.fields = name, fields self.name, self.fields = name, fields
self.classes = ' '.join(classes) self.classes = ' '.join(classes)
self.description = description self.description = description
class BoundFieldset(object):
def __init__(self, form, fieldset):
self.form, self.fieldset = form, fieldset
def __iter__(self):
for field in self.fieldset.fields:
yield BoundFieldline(self.form, field)
class BoundFieldline(object):
def __init__(self, form, field):
self.form = form # A django.forms.Form instance
if isinstance(field, basestring):
self.fields = [field]
else:
self.fields = field
def __iter__(self):
for i, field in enumerate(self.fields):
yield BoundField(self.form, field, is_first=(i == 0))
def errors(self):
return u'\n'.join([self.form[f].errors.as_ul() for f in self.fields])
class BoundField(object):
def __init__(self, form, field, is_first):
self.field = form[field] # A django.forms.BoundField instance
self.is_first = is_first # Whether this field is first on the line
self.is_checkbox = isinstance(self.field.field.widget, forms.CheckboxInput)
def label_tag(self):
classes = []
if self.is_checkbox:
classes.append('vCheckboxLabel')
contents = escape(self.field.label)
else:
contents = escape(self.field.label) + ':'
if self.field.field.required:
classes.append('required')
if not self.is_first:
classes.append('inline')
attrs = classes and {'class': ' '.join(classes)} or {}
return self.field.label_tag(contents=contents, attrs=attrs)
class ModelAdmin(object): class ModelAdmin(object):
"Encapsulates all admin options and functionality for a given model." "Encapsulates all admin options and functionality for a given model."
@ -202,18 +253,16 @@ class ModelAdmin(object):
# Object list will give 'Permission Denied', so go back to admin home # Object list will give 'Permission Denied', so go back to admin home
post_url = '../../../' post_url = '../../../'
manipulator = model.AddManipulator() ModelForm = forms.form_for_model(model)
if request.POST: if request.POST:
new_data = request.POST.copy() new_data = request.POST.copy()
if opts.has_field_type(models.FileField): if opts.has_field_type(models.FileField):
new_data.update(request.FILES) new_data.update(request.FILES)
form = ModelForm(new_data)
errors = manipulator.get_validation_errors(new_data) if form.is_valid():
manipulator.do_html2python(new_data) new_object = form.save(commit=True)
if not errors:
new_object = manipulator.save(new_data)
pk_value = new_object._get_pk_val() pk_value = new_object._get_pk_val()
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), ADDITION) LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), ADDITION)
msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object} msg = _('The %(name)s "%(obj)s" was added successfully.') % {'name': opts.verbose_name, 'obj': new_object}
@ -236,25 +285,17 @@ class ModelAdmin(object):
request.user.message_set.create(message=msg) request.user.message_set.create(message=msg)
return HttpResponseRedirect(post_url) return HttpResponseRedirect(post_url)
else: else:
# Add default data. form = ModelForm(initial=request.GET)
new_data = manipulator.flatten_data()
# Override the defaults with GET params, if they exist.
new_data.update(dict(request.GET.items()))
errors = {}
# Populate the FormWrapper.
form = oldforms.FormWrapper(manipulator, new_data, errors)
c = template.RequestContext(request, { c = template.RequestContext(request, {
'title': _('Add %s') % opts.verbose_name, 'title': _('Add %s') % opts.verbose_name,
'oldform': form, 'adminform': AdminForm(form, self.fieldsets_add(request)),
'oldform': oldforms.FormWrapper(model.AddManipulator(), {}, {}),
'is_popup': request.REQUEST.has_key('_popup'), 'is_popup': request.REQUEST.has_key('_popup'),
'show_delete': False, 'show_delete': False,
}) })
return render_change_form(self, model, manipulator, c, add=True) return render_change_form(self, model, model.AddManipulator(), c, add=True)
def change_view(self, request, object_id): def change_view(self, request, object_id):
"The 'change' admin view for this model." "The 'change' admin view for this model."
@ -272,32 +313,33 @@ class ModelAdmin(object):
return self.add_view(request, form_url='../../add/') return self.add_view(request, form_url='../../add/')
try: try:
manipulator = model.ChangeManipulator(object_id) obj = model._default_manager.get(pk=object_id)
except model.DoesNotExist: except model.DoesNotExist:
raise Http404('%s object with primary key %r does not exist' % (model_name, escape(object_id))) raise Http404('%s object with primary key %r does not exist' % (model_name, escape(object_id)))
ModelForm = forms.form_for_instance(obj)
if request.POST: if request.POST:
new_data = request.POST.copy() new_data = request.POST.copy()
if opts.has_field_type(models.FileField): if opts.has_field_type(models.FileField):
new_data.update(request.FILES) new_data.update(request.FILES)
form = ModelForm(new_data)
errors = manipulator.get_validation_errors(new_data) if form.is_valid():
manipulator.do_html2python(new_data) new_object = form.save(commit=True)
if not errors:
new_object = manipulator.save(new_data)
pk_value = new_object._get_pk_val() pk_value = new_object._get_pk_val()
# Construct the change message. # Construct the change message. TODO: Temporarily commented-out,
# as manipulator object doesn't exist anymore, and we don't yet
# have a way to get fields_added, fields_changed, fields_deleted.
change_message = [] change_message = []
if manipulator.fields_added: #if manipulator.fields_added:
change_message.append(_('Added %s.') % get_text_list(manipulator.fields_added, _('and'))) #change_message.append(_('Added %s.') % get_text_list(manipulator.fields_added, _('and')))
if manipulator.fields_changed: #if manipulator.fields_changed:
change_message.append(_('Changed %s.') % get_text_list(manipulator.fields_changed, _('and'))) #change_message.append(_('Changed %s.') % get_text_list(manipulator.fields_changed, _('and')))
if manipulator.fields_deleted: #if manipulator.fields_deleted:
change_message.append(_('Deleted %s.') % get_text_list(manipulator.fields_deleted, _('and'))) #change_message.append(_('Deleted %s.') % get_text_list(manipulator.fields_deleted, _('and')))
change_message = ' '.join(change_message) #change_message = ' '.join(change_message)
if not change_message: if not change_message:
change_message = _('No fields changed.') change_message = _('No fields changed.')
LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), CHANGE, change_message) LogEntry.objects.log_action(request.user.id, ContentType.objects.get_for_model(model).id, pk_value, str(new_object), CHANGE, change_message)
@ -319,41 +361,31 @@ class ModelAdmin(object):
request.user.message_set.create(message=msg) request.user.message_set.create(message=msg)
return HttpResponseRedirect("../") return HttpResponseRedirect("../")
else: else:
# Populate new_data with a "flattened" version of the current data. form = ModelForm()
new_data = manipulator.flatten_data()
# TODO: do this in flatten_data... ## Populate the FormWrapper.
# If the object has ordered objects on its admin page, get the existing #oldform = oldforms.FormWrapper(manipulator, new_data, errors)
# order and flatten it into a comma-separated list of IDs. #oldform.original = manipulator.original_object
id_order_list = [] #oldform.order_objects = []
for rel_obj in opts.get_ordered_objects():
id_order_list.extend(getattr(manipulator.original_object, 'get_%s_order' % rel_obj.object_name.lower())())
if id_order_list:
new_data['order_'] = ','.join(map(str, id_order_list))
errors = {}
# Populate the FormWrapper. ## TODO: Should be done in flatten_data / FormWrapper construction
form = oldforms.FormWrapper(manipulator, new_data, errors) #for related in opts.get_followed_related_objects():
form.original = manipulator.original_object #wrt = related.opts.order_with_respect_to
form.order_objects = [] #if wrt and wrt.rel and wrt.rel.to == opts:
#func = getattr(manipulator.original_object, 'get_%s_list' %
# TODO: Should be done in flatten_data / FormWrapper construction #related.get_accessor_name())
for related in opts.get_followed_related_objects(): #orig_list = func()
wrt = related.opts.order_with_respect_to #oldform.order_objects.extend(orig_list)
if wrt and wrt.rel and wrt.rel.to == opts:
func = getattr(manipulator.original_object, 'get_%s_list' %
related.get_accessor_name())
orig_list = func()
form.order_objects.extend(orig_list)
c = template.RequestContext(request, { c = template.RequestContext(request, {
'title': _('Change %s') % opts.verbose_name, 'title': _('Change %s') % opts.verbose_name,
'oldform': form, 'adminform': AdminForm(form, self.fieldsets_change(request, object_id)),
'oldform': oldforms.FormWrapper(model.ChangeManipulator(object_id), {}, {}),
'object_id': object_id, 'object_id': object_id,
'original': manipulator.original_object, 'original': obj,
'is_popup': request.REQUEST.has_key('_popup'), 'is_popup': request.REQUEST.has_key('_popup'),
}) })
return render_change_form(self, model, manipulator, c, change=True) return render_change_form(self, model, model.ChangeManipulator(object_id), c, change=True)
def changelist_view(self, request): def changelist_view(self, request):
"The 'change list' admin view for this model." "The 'change list' admin view for this model."

View File

@ -34,24 +34,34 @@
<div> <div>
{% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %} {% if is_popup %}<input type="hidden" name="_popup" value="1" />{% endif %}
{% if save_on_top %}{% submit_row %}{% endif %} {% if save_on_top %}{% submit_row %}{% endif %}
{% if oldform.error_dict %} {% if adminform.form.errors %}
<p class="errornote"> <p class="errornote">
{% blocktrans count oldform.error_dict.items|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %} {% blocktrans count adminform.form.errors.items|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
</p> </p>
{% endif %} {% endif %}
{% for bound_field_set in bound_field_sets %}
<fieldset class="module aligned {{ bound_field_set.classes }}"> {% for bfset in adminform %}
{% if bound_field_set.name %}<h2>{{ bound_field_set.name }}</h2>{% endif %} <fieldset class="module aligned {{ bfset.fieldset.classes }}">
{% if bound_field_set.description %}<div class="description">{{ bound_field_set.description }}</div>{% endif %} {% if bfset.fieldset.name %}<h2>{{ bfset.fieldset.name }}</h2>{% endif %}
{% for bound_field_line in bound_field_set %} {% if bfset.fieldset.description %}<div class="description">{{ bfset.fieldset.description }}</div>{% endif %}
{% admin_field_line bound_field_line %} {% for line in bfset %}
{% for bound_field in bound_field_line %} <div class="form-row{% if line.errors %} errors{% endif %}">
{% filter_interface_script_maybe bound_field %} {{ line.errors }}
{% for field in line %}
{% if field.is_checkbox %}
{{ field.field }}{{ field.label_tag }}
{% else %}
{{ field.label_tag }}{{ field.field }}
{% endif %}
{% if field.help_text %}<p class="help">{{ field.help_text }}</p>{% endif %}
{% endfor %} {% endfor %}
</div>
{% endfor %} {% endfor %}
</fieldset> </fieldset>
{% endfor %} {% endfor %}
{% block after_field_sets %}{% endblock %} {% block after_field_sets %}{% endblock %}
{% if change %} {% if change %}
{% if ordered_objects %} {% if ordered_objects %}
<fieldset class="module"><h2>{% trans "Ordering" %}</h2> <fieldset class="module"><h2>{% trans "Ordering" %}</h2>
@ -61,17 +71,23 @@
</div></fieldset> </div></fieldset>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% for related_object in inline_related_objects %}{% edit_inline related_object %}{% endfor %} {% for related_object in inline_related_objects %}{% edit_inline related_object %}{% endfor %}
{% block after_related_objects %}{% endblock %} {% block after_related_objects %}{% endblock %}
{% submit_row %} {% submit_row %}
{% if add %} {% if add %}
<script type="text/javascript">document.getElementById("{{ first_form_field_id }}").focus();</script> <script type="text/javascript">document.getElementById("{{ first_form_field_id }}").focus();</script>
{% endif %} {% endif %}
{% if auto_populated_fields %} {% if auto_populated_fields %}
<script type="text/javascript"> <script type="text/javascript">
{% auto_populated_field_script auto_populated_fields change %} {% auto_populated_field_script auto_populated_fields change %}
</script> </script>
{% endif %} {% endif %}
</div> </div>
</form></div> </form></div>
{% endblock %} {% endblock %}

View File

@ -1,10 +0,0 @@
{% load admin_modify %}
<div class="{{ class_names }}" >
{% for bound_field in bound_fields %}{{ bound_field.html_error_list }}{% endfor %}
{% for bound_field in bound_fields %}
{% if bound_field.has_label_first %}{% field_label bound_field %}{% endif %}
{% field_widget bound_field %}
{% if not bound_field.has_label_first %}{% field_label bound_field %}{% endif %}
{% if bound_field.field.help_text %}<p class="help">{{ bound_field.field.help_text }}</p>{% endif %}
{% endfor %}
</div>

View File

@ -48,22 +48,6 @@ def submit_row(context):
} }
submit_row = register.inclusion_tag('admin/submit_line.html', takes_context=True)(submit_row) submit_row = register.inclusion_tag('admin/submit_line.html', takes_context=True)(submit_row)
def field_label(bound_field):
class_names = []
if isinstance(bound_field.field, models.BooleanField):
class_names.append("vCheckboxLabel")
colon = ""
else:
if not bound_field.field.blank:
class_names.append('required')
if not bound_field.first:
class_names.append('inline')
colon = ":"
class_str = class_names and ' class="%s"' % ' '.join(class_names) or ''
return '<label for="%s"%s>%s%s</label> ' % (bound_field.element_id, class_str, \
capfirst(bound_field.field.verbose_name), colon)
field_label = register.simple_tag(field_label)
class FieldWidgetNode(template.Node): class FieldWidgetNode(template.Node):
nodelists = {} nodelists = {}
default = None default = None
@ -216,30 +200,3 @@ def edit_inline(parser, token):
raise template.TemplateSyntaxError, "%s takes 1 argument" % bits[0] raise template.TemplateSyntaxError, "%s takes 1 argument" % bits[0]
return EditInlineNode(bits[1]) return EditInlineNode(bits[1])
edit_inline = register.tag(edit_inline) edit_inline = register.tag(edit_inline)
def admin_field_line(context, argument_val):
if isinstance(argument_val, AdminBoundField):
bound_fields = [argument_val]
else:
bound_fields = [bf for bf in argument_val]
add = context['add']
change = context['change']
class_names = ['form-row']
for bound_field in bound_fields:
for f in bound_field.form_fields:
if f.errors():
class_names.append('errors')
break
# Assumes BooleanFields won't be stacked next to each other!
if isinstance(bound_fields[0].field, models.BooleanField):
class_names.append('checkbox-row')
return {
'add': context['add'],
'change': context['change'],
'bound_fields': bound_fields,
'class_names': " ".join(class_names),
}
admin_field_line = register.inclusion_tag('admin/field_line.html', takes_context=True)(admin_field_line)