magic-removal: Some validation fixes.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@1797 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Robert Wittams 2005-12-29 21:42:39 +00:00
parent 8fae40894a
commit 85ef615c42
5 changed files with 137 additions and 60 deletions

View File

@ -49,41 +49,43 @@ def change_stage(request, path, object_id):
#save a copy of the data to use for errors later. #save a copy of the data to use for errors later.
data = new_data.copy() data = new_data.copy()
manipulator.do_html2python(new_data) manipulator.do_html2python(new_data)
#update the manipulator with the effects of previous commands. #update the manipulator with the effects of previous commands.
manipulator.update(new_data) manipulator.update(new_data)
#get the errors on the updated shape of the manipulator #get the errors on the updated shape of the manipulator
#HACK - validators should not work on POSTED data directly... #HACK - validators should not work on POSTED data directly...
errors = manipulator.get_validation_errors(data)
if request.POST.has_key("_preview"): if request.POST.has_key("_preview"):
pass errors = manipulator.get_validation_errors(data)
elif request.POST.has_key("command"): elif request.POST.has_key("command"):
command_name = request.POST.get("command") command_name = request.POST.get("command")
manipulator.do_command(command_name) manipulator.do_command(command_name)
new_data = manipulator.flatten_data() errors = manipulator.get_validation_errors(data)
elif errors:
new_data = manipulator.flatten_data() new_data = manipulator.flatten_data()
else: else:
new_object = manipulator.save_from_update() errors = manipulator.get_validation_errors(data)
log_change_message(request.user, opts, manipulator, new_object) if errors:
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object} new_data = manipulator.flatten_data()
pk_value = getattr(new_object, opts.pk.attname)
if request.POST.has_key("_continue"):
request.user.add_message(msg + ' ' + _("You may edit it again below."))
if request.REQUEST.has_key('_popup'):
return HttpResponseRedirect(request.path + "?_popup=1")
else:
return HttpResponseRedirect(request.path)
elif request.POST.has_key("_saveasnew"):
request.user.add_message(_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object})
return HttpResponseRedirect("../../%s/" % pk_value)
elif request.POST.has_key("_addanother"):
request.user.add_message(msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
return HttpResponseRedirect("../../add/")
else: else:
request.user.add_message(msg) new_object = manipulator.save_from_update()
return HttpResponseRedirect("../../") log_change_message(request.user, opts, manipulator, new_object)
msg = _('The %(name)s "%(obj)s" was changed successfully.') % {'name': opts.verbose_name, 'obj': new_object}
pk_value = getattr(new_object, opts.pk.attname)
if request.POST.has_key("_continue"):
request.user.add_message(msg + ' ' + _("You may edit it again below."))
if request.REQUEST.has_key('_popup'):
return HttpResponseRedirect(request.path + "?_popup=1")
else:
return HttpResponseRedirect(request.path)
elif request.POST.has_key("_saveasnew"):
request.user.add_message(_('The %(name)s "%(obj)s" was added successfully. You may edit it again below.') % {'name': opts.verbose_name, 'obj': new_object})
return HttpResponseRedirect("../../%s/" % pk_value)
elif request.POST.has_key("_addanother"):
request.user.add_message(msg + ' ' + (_("You may add another %s below.") % opts.verbose_name))
return HttpResponseRedirect("../../add/")
else:
request.user.add_message(msg)
return HttpResponseRedirect("../../")
else: else:
# Populate new_data with a "flattened" version of the current data. # Populate new_data with a "flattened" version of the current data.
new_data = manipulator.flatten_data() new_data = manipulator.flatten_data()

View File

@ -55,26 +55,35 @@ class Manipulator(object):
"Returns dictionary mapping field_names to error-message lists" "Returns dictionary mapping field_names to error-message lists"
errors = {} errors = {}
for field in self.fields: for field in self.fields:
if field.is_required and not new_data.get(field.field_name, False): errors.update(field.get_validation_errors(new_data))
errors.setdefault(field.field_name, []).append(gettext_lazy('This field is required.')) val_name = 'validate_%s' % field.field_name
continue if hasattr(self, val_name):
try: val = getattr(self, val_name)
validator_list = field.validator_list try:
if hasattr(self, 'validate_%s' % field.field_name): field.run_validator(new_data, val)
validator_list.append(getattr(self, 'validate_%s' % field.field_name)) except (validators.ValidationError, validators.CriticalValidationError), e:
for validator in validator_list: errors.setdefault(field.field_name, []).extend(e.messages)
if field.is_required or new_data.get(field.field_name, False) or hasattr(validator, 'always_test'):
try: # if field.is_required and not new_data.get(field.field_name, False):
if hasattr(field, 'requires_data_list'): # errors.setdefault(field.field_name, []).append(gettext_lazy('This field is required.'))
validator(new_data.getlist(field.field_name), new_data) # continue
else: # try:
validator(new_data.get(field.field_name, ''), new_data) # validator_list = field.validator_list
except validators.ValidationError, e: # if hasattr(self, 'validate_%s' % field.field_name):
errors.setdefault(field.field_name, []).extend(e.messages) # validator_list.append(getattr(self, 'validate_%s' % field.field_name))
# If a CriticalValidationError is raised, ignore any other ValidationErrors # for validator in validator_list:
# for this particular field # if field.is_required or new_data.get(field.field_name, False) or hasattr(validator, 'always_test'):
except validators.CriticalValidationError, e: # try:
errors.setdefault(field.field_name, []).extend(e.messages) # if hasattr(field, 'requires_data_list'):
# validator(new_data.getlist(field.field_name), new_data)
# else:
# validator(new_data.get(field.field_name, ''), new_data)
# except validators.ValidationError, e:
# errors.setdefault(field.field_name, []).extend(e.messages)
# # If a CriticalValidationError is raised, ignore any other ValidationErrors
# # for this particular field
# except validators.CriticalValidationError, e:
# errors.setdefault(field.field_name, []).extend(e.messages)
return errors return errors
def save(self, new_data): def save(self, new_data):
@ -89,6 +98,7 @@ class Manipulator(object):
must happen after validation because html2python functions aren't must happen after validation because html2python functions aren't
expected to deal with invalid input. expected to deal with invalid input.
""" """
print "converting for ", self, self.fields
for field in self.fields: for field in self.fields:
field.convert_post_data(new_data) field.convert_post_data(new_data)
@ -314,12 +324,37 @@ class FormField:
except ValueError: except ValueError:
converted_data = d converted_data = d
new_data.setlist(name, converted_data) new_data.setlist(name, converted_data)
# else: else:
# try: try:
# # individual fields deal with None values themselves #individual fields deal with None values themselves
# new_data.setlist(name, [self.__class__.html2python(None)]) new_data.setlist(name, [self.__class__.html2python(None)])
# except EmptyValue: except EmptyValue:
# new_data.setlist(name, []) new_data.setlist(name, [])
def run_validator(self, new_data, validator):
if self.is_required or new_data.get(self.field_name, False) or hasattr(validator, 'always_test'):
if hasattr(self, 'requires_data_list'):
validator(new_data.getlist(self.field_name), new_data)
else:
validator(new_data.get(self.field_name, ''), new_data)
def get_validation_errors(self, new_data):
errors = {}
if self.is_required and not new_data.get(self.field_name, False):
errors.setdefault(self.field_name, []).append(gettext_lazy('This field is required.'))
return errors
try:
for validator in self.validator_list:
try:
self.run_validator(new_data, validator)
except validators.ValidationError, e:
errors.setdefault(self.field_name, []).extend(e.messages)
# If a CriticalValidationError is raised, ignore any other ValidationErrors
# for this particular field
except validators.CriticalValidationError, e:
errors.setdefault(self.field_name, []).extend(e.messages)
return errors
def get_id(self): def get_id(self):
"Returns the HTML 'id' attribute for this form field." "Returns the HTML 'id' attribute for this form field."

View File

@ -1,6 +1,6 @@
import django.db.models.manipulators import django.db.models.manipulators
import django.db.models.manager import django.db.models.manager
from django.db.models.fields import AutoField, ImageField from django.db.models.fields import AutoField, ImageField, Admin
from django.db.models.fields.related import OneToOne, ManyToOne from django.db.models.fields.related import OneToOne, ManyToOne
from django.db.models.related import RelatedObject from django.db.models.related import RelatedObject
from django.db.models.query import orderlist2sql from django.db.models.query import orderlist2sql
@ -20,7 +20,7 @@ import os
if not hasattr(__builtins__, 'set'): if not hasattr(__builtins__, 'set'):
from sets import Set as set from sets import Set as set
attribute_transforms = {} attribute_transforms = { 'Admin': lambda cls: Admin(**cls.__dict__) }
class ModelBase(type): class ModelBase(type):
"Metaclass for all models" "Metaclass for all models"

View File

@ -726,7 +726,7 @@ class OrderingField(IntegerField):
return "IntegerField" return "IntegerField"
def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):
return [HiddenField(name_prefix + self.name) ] return [formfields.HiddenField(name_prefix + self.name) ]
def contribute_to_class(self, cls, name): def contribute_to_class(self, cls, name):
super(OrderingField, self ).contribute_to_class(cls, name) super(OrderingField, self ).contribute_to_class(cls, name)
@ -819,3 +819,6 @@ class Admin:
line_specs = fs_options['fields'] line_specs = fs_options['fields']
new_fieldset_list.append(FieldSet(name, classes, opts.get_field, line_specs)) new_fieldset_list.append(FieldSet(name, classes, opts.get_field, line_specs))
return new_fieldset_list return new_fieldset_list
def contribute_to_class(self, cls, name):
cls._meta.admin = self

View File

@ -99,20 +99,38 @@ class AutomaticManipulator(Manipulator, Naming):
if manipulators != None: if manipulators != None:
self.children[f] = manipulators self.children[f] = manipulators
self.needs_deletion = False self.needs_deletion = False
self.ignore_errors = False
def get_fields(self): def get_fields(self):
if self.needs_deletion: if self.needs_deletion :
return [] return []
else: else:
l = list(self.fields_) return self.fields_
for child_manips in self.children.values(): #l = list(self.fields_)
for manip in child_manips: #for child_manips in self.children.values():
if manip: # for manip in child_manips:
l.extend(manip.fields) # if manip:
return l # l.extend(manip.fields)
#return l
fields = property(get_fields) fields = property(get_fields)
def get_validation_errors(self, new_data):
"Returns dictionary mapping field_names to error-message lists"
if self.needs_deletion or self.ignore_errors:
return {}
errors = super(AutomaticManipulator, self).get_validation_errors(new_data)
for manips in self.children.values():
errors.update(manips.get_validation_errors(new_data))
return errors
def do_html2python(self, new_data):
super(AutomaticManipulator, self).do_html2python(new_data)
for child in self.children.values():
child.do_html2python(new_data)
def get_original_value(self, field): def get_original_value(self, field):
raise NotImplemented raise NotImplemented
@ -358,6 +376,8 @@ class ManipulatorCollection(list, Naming):
items.sort(cmp = lambda x, y: cmp(x[0], y[0])) items.sort(cmp = lambda x, y: cmp(x[0], y[0]))
for index, obj_data in items: for index, obj_data in items:
child_manip = self.add_child(index) child_manip = self.add_child(index)
#HACK: this data will not have been converted to python form yet.
#child_manip.do_html2python(obj_data)
child_manip._fill_data(obj_data) child_manip._fill_data(obj_data)
def _do_command_expanded(self, command_parts): def _do_command_expanded(self, command_parts):
@ -384,7 +404,9 @@ class ManipulatorCollection(list, Naming):
# add. # add.
# TODO: page.forward, page.back, page.n, swap.n.m # TODO: page.forward, page.back, page.n, swap.n.m
if command_name == "add": if command_name == "add":
self.add_child() child_manip = self.add_child()
# Don't show validation stuff for things just added.
child_manip.ignore_errors = True
elif command_name == "swap": elif command_name == "swap":
order_field = self.model._meta.order_with_respect_to order_field = self.model._meta.order_with_respect_to
if not order_field: if not order_field:
@ -417,6 +439,7 @@ class ManipulatorCollection(list, Naming):
prefix = '%s%s.' % (self.name_prefix, index ) prefix = '%s%s.' % (self.name_prefix, index )
child_manip = man_class(self.follow, self.name_parts + ( str(index), ) ) child_manip = man_class(self.follow, self.name_parts + ( str(index), ) )
self[index] = child_manip self[index] = child_manip
return child_manip return child_manip
@ -427,6 +450,20 @@ class ManipulatorCollection(list, Naming):
manip_data = manip.flatten_data() manip_data = manip.flatten_data()
new_data.update(manip_data) new_data.update(manip_data)
return new_data return new_data
def get_validation_errors(self, new_data):
"Returns dictionary mapping field_names to error-message lists"
errors = {}
for manip in self:
if manip:
errors.update(manip.get_validation_errors(new_data))
return errors
def do_html2python(self, new_data):
print "coll: ", self
for manip in self:
if manip:
manip.do_html2python(new_data)
def manipulator_validator_unique_together(field_name_list, opts, self, field_data, all_data): def manipulator_validator_unique_together(field_name_list, opts, self, field_data, all_data):
from django.db.models.fields.related import ManyToOne from django.db.models.fields.related import ManyToOne