Changeset 8616
- Timestamp:
- 08/27/08 02:19:44 (10 months ago)
- Files:
-
- django/trunk/django/contrib/admin/util.py (modified) (3 diffs)
- django/trunk/django/contrib/auth/management/commands/createsuperuser.py (modified) (3 diffs)
- django/trunk/django/contrib/auth/models.py (modified) (1 diff)
- django/trunk/django/contrib/comments/forms.py (modified) (1 diff)
- django/trunk/django/contrib/comments/models.py (modified) (1 diff)
- django/trunk/django/contrib/contenttypes/generic.py (modified) (6 diffs)
- django/trunk/django/contrib/flatpages/models.py (modified) (1 diff)
- django/trunk/django/contrib/localflavor/jp/forms.py (modified) (1 diff)
- django/trunk/django/core/exceptions.py (modified) (1 diff)
- django/trunk/django/core/serializers/base.py (modified) (1 diff)
- django/trunk/django/core/validators.py (deleted)
- django/trunk/django/db/models/base.py (modified) (2 diffs)
- django/trunk/django/db/models/fields/files.py (modified) (5 diffs)
- django/trunk/django/db/models/fields/__init__.py (modified) (43 diffs)
- django/trunk/django/db/models/fields/related.py (modified) (15 diffs)
- django/trunk/django/db/models/__init__.py (modified) (2 diffs)
- django/trunk/django/db/models/manipulators.py (deleted)
- django/trunk/django/db/models/options.py (modified) (2 diffs)
- django/trunk/django/db/models/related.py (modified) (1 diff)
- django/trunk/django/forms/fields.py (modified) (2 diffs)
- django/trunk/django/oldforms (deleted)
- django/trunk/docs/howto/custom-model-fields.txt (modified) (3 diffs)
- django/trunk/docs/intro/whatsnext.txt (modified) (1 diff)
- django/trunk/docs/obsolete/forms.txt (deleted)
- django/trunk/docs/obsolete/newforms-migration.txt (deleted)
- django/trunk/docs/ref/forms/fields.txt (modified) (1 diff)
- django/trunk/docs/ref/models/fields.txt (modified) (3 diffs)
- django/trunk/docs/topics/forms/modelforms.txt (modified) (1 diff)
- django/trunk/docs/topics/testing.txt (modified) (1 diff)
- django/trunk/tests/modeltests/field_subclassing/models.py (modified) (1 diff)
- django/trunk/tests/modeltests/invalid_models/models.py (modified) (4 diffs)
- django/trunk/tests/modeltests/manipulators (deleted)
- django/trunk/tests/modeltests/mutually_referential/models.py (modified) (1 diff)
- django/trunk/tests/regressiontests/model_fields/tests.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/trunk/django/contrib/admin/util.py
r8575 r8616 86 86 # We don't care about populating deleted_objects now. 87 87 continue 88 if related.field.rel.edit_inline ornot has_admin:88 if not has_admin: 89 89 # Don't display link to edit, because it either has no 90 90 # admin or is edited inline. … … 102 102 for sub_obj in getattr(obj, rel_opts_name).all(): 103 103 has_related_objs = True 104 if related.field.rel.edit_inline ornot has_admin:104 if not has_admin: 105 105 # Don't display link to edit, because it either has no 106 106 # admin or is edited inline. … … 133 133 if has_related_objs: 134 134 for sub_obj in rel_objs.all(): 135 if related.field.rel.edit_inline ornot has_admin:135 if not has_admin: 136 136 # Don't display link to edit, because it either has no 137 137 # admin or is edited inline. django/trunk/django/contrib/auth/management/commands/createsuperuser.py
r8046 r8616 9 9 from optparse import make_option 10 10 from django.contrib.auth.models import User 11 from django.core import validators11 from django.core import exceptions 12 12 from django.core.management.base import BaseCommand, CommandError 13 from django.utils.translation import ugettext as _ 13 14 14 15 RE_VALID_USERNAME = re.compile('\w+$') 16 EMAIL_RE = re.compile( 17 r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom 18 r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string 19 r')@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain 20 21 def is_valid_email(value): 22 if not EMAIL_RE.search(value): 23 raise exceptions.ValidationError(_('Enter a valid e-mail address.')) 15 24 16 25 class Command(BaseCommand): … … 40 49 raise CommandError("Invalid username. Use only letters, digits, and underscores") 41 50 try: 42 validators.isValidEmail(email, None)43 except validators.ValidationError:51 is_valid_email(email) 52 except exceptions.ValidationError: 44 53 raise CommandError("Invalid email address.") 45 54 … … 95 104 email = raw_input('E-mail address: ') 96 105 try: 97 validators.isValidEmail(email, None)98 except validators.ValidationError:106 is_valid_email(email) 107 except exceptions.ValidationError: 99 108 sys.stderr.write("Error: That e-mail address is invalid.\n") 100 109 email = None django/trunk/django/contrib/auth/models.py
r8543 r8616 1 1 from django.contrib import auth 2 from django.core import validators3 2 from django.core.exceptions import ImproperlyConfigured 4 3 from django.db import models django/trunk/django/contrib/comments/forms.py
r8557 r8616 118 118 comment = self.cleaned_data["comment"] 119 119 if settings.COMMENTS_ALLOW_PROFANITIES == False: 120 # Logic adapted from django.core.validators; it's not clear if they121 # should be used in newforms or will be deprecated along with the122 # rest of oldforms123 120 bad_words = [w for w in settings.PROFANITIES_LIST if w in comment.lower()] 124 121 if bad_words: django/trunk/django/contrib/comments/models.py
r8614 r8616 6 6 from django.contrib.sites.models import Site 7 7 from django.db import models 8 from django.core import urlresolvers , validators8 from django.core import urlresolvers 9 9 from django.utils.translation import ugettext_lazy as _ 10 10 from django.conf import settings django/trunk/django/contrib/contenttypes/generic.py
r8608 r8616 3 3 """ 4 4 5 from django import oldforms6 5 from django.core.exceptions import ObjectDoesNotExist 7 6 from django.db import connection … … 10 9 from django.db.models.fields.related import RelatedField, Field, ManyToManyRel 11 10 from django.db.models.loading import get_model 12 from django.utils.functional import curry13 14 11 from django.forms import ModelForm 15 12 from django.forms.models import BaseModelFormSet, modelformset_factory, save_instance 16 13 from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets 14 from django.utils.encoding import smart_unicode 17 15 18 16 class GenericForeignKey(object): … … 121 119 Field.__init__(self, **kwargs) 122 120 123 def get_manipulator_field_objs(self):124 choices = self.get_choices_default()125 return [curry(oldforms.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)]126 127 121 def get_choices_default(self): 128 122 return Field.get_choices(self, include_blank=False) 129 123 130 def flatten_data(self, follow, obj = None): 131 new_data = {} 132 if obj: 133 instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()] 134 new_data[self.name] = instance_ids 135 return new_data 124 def value_to_string(self, obj): 125 qs = getattr(obj, self.name).all() 126 return smart_unicode([instance._get_pk_val() for instance in qs]) 136 127 137 128 def m2m_db_table(self): … … 291 282 self.related_name = related_name 292 283 self.limit_choices_to = limit_choices_to or {} 293 self.edit_inline = False294 284 self.symmetrical = symmetrical 295 285 self.multiple = True … … 301 291 ct_field_name = "content_type" 302 292 ct_fk_field_name = "object_id" 303 293 304 294 def __init__(self, data=None, files=None, instance=None, save_as_new=None): 305 295 opts = self.model._meta … … 396 386 class GenericTabularInline(GenericInlineModelAdmin): 397 387 template = 'admin/edit_inline/tabular.html' 398 django/trunk/django/contrib/flatpages/models.py
r8292 r8616 1 from django.core import validators2 1 from django.db import models 3 2 from django.contrib.sites.models import Site django/trunk/django/contrib/localflavor/jp/forms.py
r7971 r8616 3 3 """ 4 4 5 from django.core import validators6 5 from django.forms import ValidationError 7 6 from django.utils.translation import ugettext_lazy as _ django/trunk/django/core/exceptions.py
r7477 r8616 33 33 pass 34 34 35 class ValidationError(Exception): 36 """An error while validating data.""" 37 pass django/trunk/django/core/serializers/base.py
r8151 r8616 58 58 Convert a field's value to a string. 59 59 """ 60 if isinstance(field, models.DateTimeField): 61 d = datetime_safe.new_datetime(getattr(obj, field.name)) 62 value = d.strftime("%Y-%m-%d %H:%M:%S") 63 else: 64 value = field.flatten_data(follow=None, obj=obj).get(field.name, "") 65 return smart_unicode(value) 60 return smart_unicode(field.value_to_string(obj)) 66 61 67 62 def start_serialization(self): django/trunk/django/db/models/base.py
r8348 r8616 9 9 from sets import Set as set # Python 2.3 fallback. 10 10 11 import django.db.models.manipulators # Imported to register signal handler. 12 import django.db.models.manager # Ditto. 13 from django.core import validators 11 import django.db.models.manager # Imported to register signal handler. 14 12 from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError 15 13 from django.db.models.fields import AutoField … … 321 319 # First, try an UPDATE. If that doesn't update anything, do an INSERT. 322 320 pk_val = self._get_pk_val(meta) 323 # Note: the comparison with '' is required for compatibility with 324 # oldforms-style model creation. 325 pk_set = pk_val is not None and smart_unicode(pk_val) != u'' 321 pk_set = pk_val is not None 326 322 record_exists = True 327 323 manager = cls._default_manager django/trunk/django/db/models/fields/files.py
r8291 r8616 12 12 from django.utils.encoding import force_unicode, smart_str 13 13 from django.utils.translation import ugettext_lazy, ugettext as _ 14 from django import oldforms15 14 from django import forms 16 from django.core import validators17 15 from django.db.models.loading import cache 18 16 … … 127 125 128 126 def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs): 129 for arg in (' core', 'primary_key', 'unique'):127 for arg in ('primary_key', 'unique'): 130 128 if arg in kwargs: 131 129 raise TypeError("'%s' is not a valid argument for %s." % (arg, self.__class__)) … … 153 151 return None 154 152 return unicode(value) 155 156 def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):157 field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)158 if not self.blank:159 if rel:160 # This validator makes sure FileFields work in a related context.161 class RequiredFileField(object):162 def __init__(self, other_field_names, other_file_field_name):163 self.other_field_names = other_field_names164 self.other_file_field_name = other_file_field_name165 self.always_test = True166 def __call__(self, field_data, all_data):167 if not all_data.get(self.other_file_field_name, False):168 c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required."))169 c(field_data, all_data)170 # First, get the core fields, if any.171 core_field_names = []172 for f in opts.fields:173 if f.core and f != self:174 core_field_names.extend(f.get_manipulator_field_names(name_prefix))175 # Now, if there are any, add the validator to this FormField.176 if core_field_names:177 field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name))178 else:179 v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required."))180 v.always_test = True181 field_list[0].validator_list.append(v)182 field_list[0].is_required = field_list[1].is_required = False183 184 # If the raw path is passed in, validate it's under the MEDIA_ROOT.185 def isWithinMediaRoot(field_data, all_data):186 f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data))187 if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))):188 raise validators.ValidationError(_("Enter a valid filename."))189 field_list[1].validator_list.append(isWithinMediaRoot)190 return field_list191 153 192 154 def contribute_to_class(self, cls, name): … … 207 169 file.close() 208 170 209 def get_manipulator_field_objs(self): 210 return [oldforms.FileUploadField, oldforms.HiddenField] 211 212 def get_manipulator_field_names(self, name_prefix): 213 return [name_prefix + self.name + '_file', name_prefix + self.name] 214 215 def save_file(self, new_data, new_object, original_object, change, rel, save=True): 216 upload_field_name = self.get_manipulator_field_names('')[0] 171 def save_file(self, new_data, new_object, original_object, change, rel, 172 save=True): 173 upload_field_name = self.name + '_file' 217 174 if new_data.get(upload_field_name, False): 218 175 if rel: … … 283 240 FileField.__init__(self, verbose_name, name, **kwargs) 284 241 285 def get_manipulator_field_objs(self):286 return [oldforms.ImageUploadField, oldforms.HiddenField]287 288 242 def formfield(self, **kwargs): 289 243 defaults = {'form_class': forms.ImageField} django/trunk/django/db/models/fields/__init__.py
r8528 r8616 2 2 import datetime 3 3 import os 4 import re 4 5 import time 5 6 try: … … 13 14 from django.dispatch import dispatcher 14 15 from django.conf import settings 15 from django.core import validators16 from django import oldforms17 16 from django import forms 18 from django.core .exceptions import ObjectDoesNotExist17 from django.core import exceptions 19 18 from django.utils.datastructures import DictWrapper 20 19 from django.utils.functional import curry … … 34 33 class FieldDoesNotExist(Exception): 35 34 pass 36 37 def manipulator_validator_unique(f, opts, self, field_data, all_data):38 "Validates that the value is unique for this field."39 lookup_type = f.get_validator_unique_lookup_type()40 try:41 old_obj = self.manager.get(**{lookup_type: field_data})42 except ObjectDoesNotExist:43 return44 if getattr(self, 'original_object', None) and self.original_object._get_pk_val() == old_obj._get_pk_val():45 return46 raise validators.ValidationError, _("%(optname)s with this %(fieldname)s already exists.") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name}47 35 48 36 # A guide to Field parameters: … … 74 62 def __init__(self, verbose_name=None, name=None, primary_key=False, 75 63 max_length=None, unique=False, blank=False, null=False, 76 db_index=False, core=False, rel=None, default=NOT_PROVIDED, 77 editable=True, serialize=True, unique_for_date=None, 78 unique_for_month=None, unique_for_year=None, validator_list=None, 79 choices=None, help_text='', db_column=None, db_tablespace=None, 80 auto_created=False): 64 db_index=False, rel=None, default=NOT_PROVIDED, editable=True, 65 serialize=True, unique_for_date=None, unique_for_month=None, 66 unique_for_year=None, choices=None, help_text='', db_column=None, 67 db_tablespace=None, auto_created=False): 81 68 self.name = name 82 69 self.verbose_name = verbose_name … … 88 75 if self.empty_strings_allowed and connection.features.interprets_empty_strings_as_nulls: 89 76 self.null = True 90 self.core, self.rel, self.default = core, rel, default 77 self.rel = rel 78 self.default = default 91 79 self.editable = editable 92 80 self.serialize = serialize 93 self.validator_list = validator_list or []94 81 self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month 95 82 self.unique_for_year = unique_for_year … … 127 114 """ 128 115 Converts the input value into the expected Python data type, raising 129 validators.ValidationError if the data can't be converted. Returns the130 converted value. Subclasses should override this.116 django.core.exceptions.ValidationError if the data can't be converted. 117 Returns the converted value. Subclasses should override this. 131 118 """ 132 119 return value … … 253 240 return "" 254 241 255 def get_manipulator_field_names(self, name_prefix):256 """257 Returns a list of field names that this object adds to the manipulator.258 """259 return [name_prefix + self.name]260 261 def prepare_field_objs_and_params(self, manipulator, name_prefix):262 params = {'validator_list': self.validator_list[:]}263 if self.max_length and not self.choices: # Don't give SelectFields a max_length parameter.264 params['max_length'] = self.max_length265 266 if self.choices:267 field_objs = [oldforms.SelectField]268 269 params['choices'] = self.get_flatchoices()270 else:271 field_objs = self.get_manipulator_field_objs()272 return (field_objs, params)273 274 def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):275 """276 Returns a list of oldforms.FormField instances for this field. It277 calculates the choices at runtime, not at compile time.278 279 name_prefix is a prefix to prepend to the "field_name" argument.280 rel is a boolean specifying whether this field is in a related context.281 """282 field_objs, params = self.prepare_field_objs_and_params(manipulator, name_prefix)283 284 # Add the "unique" validator(s).285 for field_name_list in opts.unique_together:286 if field_name_list[0] == self.name:287 params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list)))288 289 # Add the "unique for..." validator(s).290 if self.unique_for_date:291 params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_date)))292 if self.unique_for_month:293 params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month)))294 if self.unique_for_year:295 params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_year)))296 if self.unique and not rel:297 params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator))298 299 # Only add is_required=True if the field cannot be blank. Primary keys300 # are a special case, and fields in a related context should set this301 # as False, because they'll be caught by a separate validator --302 # RequiredIfOtherFieldGiven.303 params['is_required'] = not self.blank and not self.primary_key and not rel304 305 # BooleanFields (CheckboxFields) are a special case. They don't take306 # is_required.307 if isinstance(self, BooleanField):308 del params['is_required']309 310 # If this field is in a related context, check whether any other fields311 # in the related object have core=True. If so, add a validator --312 # RequiredIfOtherFieldsGiven -- to this FormField.313 if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField):314 # First, get the core fields, if any.315 core_field_names = []316 for f in opts.fields:317 if f.core and f != self:318 core_field_names.extend(f.get_manipulator_field_names(name_prefix))319 # Now, if there are any, add the validator to this FormField.320 if core_field_names:321 params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, ugettext_lazy("This field is required.")))322 323 # Finally, add the field_names.324 field_names = self.get_manipulator_field_names(name_prefix)325 return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)]326 327 242 def get_validator_unique_lookup_type(self): 328 243 return '%s__exact' % self.name 329 330 def get_manipulator_new_data(self, new_data, rel=False):331 """332 Given the full new_data dictionary (from the manipulator), returns this333 field's data.334 """335 if rel:336 return new_data.get(self.name, [self.get_default()])[0]337 val = new_data.get(self.name, self.get_default())338 if not self.empty_strings_allowed and val == '' and self.null:339 val = None340 return val341 244 342 245 def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH): … … 367 270 return self.get_default() 368 271 369 def flatten_data(self, follow, obj=None):272 def value_to_string(self, obj): 370 273 """ 371 Returns a dictionary mapping the field's manipulator field names to its 372 "flattened" string values for the admin view. obj is the instance to 373 extract the values from. 274 Returns a string value of this field from the passed obj. 275 This is used by the serialization framework. 374 276 """ 375 return {self.attname: self._get_val_from_obj(obj)} 376 377 def get_follow(self, override=None): 378 if override != None: 379 return override 380 else: 381 return self.editable 277 return smart_unicode(self._get_val_from_obj(obj)) 382 278 383 279 def bind(self, fieldmapping, original, bound_field_class): … … 433 329 return int(value) 434 330 except (TypeError, ValueError): 435 raise validators.ValidationError, _("This value must be an integer.") 331 raise exceptions.ValidationError( 332 _("This value must be an integer.")) 436 333 437 334 def get_db_prep_value(self, value): … … 439 336 return None 440 337 return int(value) 441 442 def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True):443 if not rel:444 return [] # Don't add a FormField unless it's in a related context.445 return Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow)446 447 def get_manipulator_field_objs(self):448 return [oldforms.HiddenField]449 450 def get_manipulator_new_data(self, new_data, rel=False):451 # Never going to be called452 # Not in main change pages453 # ignored in related context454 if not rel:455 return None456 return Field.get_manipulator_new_data(self, new_data, rel)457 338 458 339 def contribute_to_class(self, cls, name): … … 479 360 if value in ('t', 'True', '1'): return True 480 361 if value in ('f', 'False', '0'): return False 481 raise validators.ValidationError, _("This value must be either True or False.") 362 raise exceptions.ValidationError( 363 _("This value must be either True or False.")) 482 364 483 365 def get_db_prep_value(self, value): … … 486 368 return bool(value) 487 369 488 def get_manipulator_field_objs(self):489 return [oldforms.CheckboxField]490 491 370 def formfield(self, **kwargs): 492 371 defaults = {'form_class': forms.BooleanField} … … 495 374 496 375 class CharField(Field): 497 def get_manipulator_field_objs(self):498 return [oldforms.TextField]499 500 376 def get_internal_type(self): 501 377 return "CharField" … … 508 384 return value 509 385 else: 510 raise validators.ValidationError, ugettext_lazy("This field cannot be null.") 386 raise exceptions.ValidationError( 387 ugettext_lazy("This field cannot be null.")) 511 388 return smart_unicode(value) 512 389 … … 518 395 # TODO: Maybe move this into contrib, because it's specialized. 519 396 class CommaSeparatedIntegerField(CharField): 520 def get_manipulator_field_objs(self): 521 return [oldforms.CommaSeparatedIntegerField] 397 pass 398 399 ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$') 522 400 523 401 class DateField(Field): … … 541 419 if isinstance(value, datetime.date): 542 420 return value 543 validators.isValidANSIDate(value, None) 421 422 if not ansi_date_re.search(value): 423 raise exceptions.ValidationError( 424 _('Enter a valid date in YYYY-MM-DD format.')) 425 # Now that we have the date string in YYYY-MM-DD format, check to make 426 # sure it's a valid date. 427 # We could use time.strptime here and catch errors, but datetime.date 428 # produces much friendlier error messages. 429 year, month, day = map(int, value.split('-')) 544 430 try: 545 return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3]) 546 except ValueError: 547 raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.') 431 return datetime.date(year, month, day) 432 except ValueError, e: 433 msg = _('Invalid date: %s') % _(str(e)) 434 raise exceptions.ValidationError(msg) 548 435 549 436 def pre_save(self, model_instance, add): … … 563 450 curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False)) 564 451 565 # Needed because of horrible auto_now[_add] behaviour wrt. editable566 def get_follow(self, override=None):567 if override != None:568 return override569 else:570 return self.editable or self.auto_now or self.auto_now_add571 572 452 def get_db_prep_lookup(self, lookup_type, value): 573 453 # For "__month" and "__day" lookups, convert the value to a string so … … 581 461 return connection.ops.value_to_db_date(self.to_python(value)) 582 462 583 def get_manipulator_field_objs(self): 584 return [oldforms.DateField] 585 586 def flatten_data(self, follow, obj=None): 463 def value_to_string(self, obj): 587 464 val = self._get_val_from_obj(obj) 588 465 if val is None: … … 590 467 else: 591 468 data = datetime_safe.new_date(val).strftime("%Y-%m-%d") 592 return {self.attname: data}469 return data 593 470 594 471 def formfield(self, **kwargs): … … 617 494 usecs = int(usecs) 618 495 except ValueError: 619 raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.') 496 raise exceptions.ValidationError( 497 _('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.')) 620 498 else: 621 499 usecs = 0 … … 634 512 **kwargs) 635 513 except ValueError: 636 raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.') 514 raise exceptions.ValidationError( 515 _('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.')) 637 516 638 517 def get_db_prep_value(self, value): … … 640 519 return connection.ops.value_to_db_datetime(self.to_python(value)) 641 520 642 def get_manipulator_field_objs(self): 643 return [oldforms.DateField, oldforms.TimeField] 644 645 def get_manipulator_field_names(self, name_prefix): 646 return [name_prefix + self.name + '_date', name_prefix + self.name + '_time'] 647 648 def get_manipulator_new_data(self, new_data, rel=False): 649 date_field, time_field = self.get_manipulator_field_names('') 650 if rel: 651 d = new_data.get(date_field, [None])[0] 652 t = new_data.get(time_field, [None])[0] 653 else: 654 d = new_data.get(date_field, None) 655 t = new_data.get(time_field, None) 656 if d is not None and t is not None: 657 return datetime.datetime.combine(d, t) 658 return self.get_default() 659 660 def flatten_data(self,follow, obj = None): 521 def value_to_string(self, obj): 661 522 val = self._get_val_from_obj(obj) 662 date_field, time_field = self.get_manipulator_field_names('')663 523 if val is None: 664 dat e_data = time_data = ''524 data = '' 665 525 else: 666 526 d = datetime_safe.new_datetime(val) 667 date_data = d.strftime('%Y-%m-%d') 668 time_data = d.strftime('%H:%M:%S') 669 return {date_field: date_data, time_field: time_data} 527 data = d.strftime('%Y-%m-%d %H:%M:%S') 528 return data 670 529 671 530 def formfield(self, **kwargs): … … 689 548 return decimal.Decimal(value) 690 549 except decimal.InvalidOperation: 691 raise validators.ValidationError(550 raise exceptions.ValidationError( 692 551 _("This value must be a decimal number.")) 693 552 … … 716 575 self.max_digits, self.decimal_places) 717 576 718 def get_manipulator_field_objs(self):719 return [curry(oldforms.DecimalField, max_digits=self.max_digits, decimal_places=self.decimal_places)]720 721 577 def formfield(self, **kwargs): 722 578 defaults = { … … 732 588 kwargs['max_length'] = kwargs.get('max_length', 75) 733 589 CharField.__init__(self, *args, **kwargs) 734 735 def get_manipulator_field_objs(self):736 return [oldforms.EmailField]737 590 738 591 def formfield(self, **kwargs): … … 757 610 return super(FilePathField, self).formfield(**defaults) 758 611 759 def get_manipulator_field_objs(self):760 return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)]761 762 612 def get_internal_type(self): 763 613 return "FilePathField" … … 771 621 return float(value) 772 622 773 def get_manipulator_field_objs(self):774 return [oldforms.FloatField]775 776 623 def get_internal_type(self): 777 624 return "FloatField" … … 788 635 return None 789 636 return int(value) 790 791 def get_manipulator_field_objs(self):792 return [oldforms.IntegerField]793 637 794 638 def get_internal_type(self): … … 801 645 return int(value) 802 646 except (TypeError, ValueError): 803 raise validators.ValidationError, _("This value must be an integer.") 804 647 raise exceptions.ValidationError( 648 _("This value must be an integer.")) 649 805 650 def formfield(self, **kwargs): 806 651 defaults = {'form_class': forms.IntegerField} … … 814 659 Field.__init__(self, *args, **kwargs) 815 660 816 def get_manipulator_field_objs(self):817 return [oldforms.IPAddressField]818 819 661 def get_internal_type(self): 820 662 return "IPAddressField" … … 839 681 if value in ('t', 'True', '1'): return True 840 682 if value in ('f', 'False', '0'): return False 841 raise validators.ValidationError, _("This value must be either None, True or False.") 683 raise exceptions.ValidationError( 684 _("This value must be either None, True or False.")) 842 685 843 686 def get_db_prep_value(self, value): … … 845 688 return None 846 689 return bool(value) 847 848 def get_manipulator_field_objs(self):849 return [oldforms.NullBooleanField]850 690 851 691 def formfield(self, **kwargs): … … 859 699 860 700 class PhoneNumberField(Field): 861 def get_manipulator_field_objs(self):862 return [oldforms.PhoneNumberField]863 864 701 def get_internal_type(self): 865 702 return "PhoneNumberField" … … 872 709 873 710 class PositiveIntegerField(IntegerField): 874 def get_manipulator_field_objs(self):875 return [oldforms.PositiveIntegerField]876 877 711 def get_internal_type(self): 878 712 return "PositiveIntegerField" … … 884 718 885 719 class PositiveSmallIntegerField(IntegerField): 886 def get_manipulator_field_objs(self):887 return [oldforms.PositiveSmallIntegerField]888 889 720 def get_internal_type(self): 890 721 return "PositiveSmallIntegerField" … … 898 729 def __init__(self, *args, **kwargs): 899 730 kwargs['max_length'] = kwargs.get('max_length', 50) 900 kwargs.setdefault('validator_list', []).append(validators.isSlug)901 731 # Set db_index=True unless it's been set manually. 902 732 if 'db_index' not in kwargs: … … 908 738 909 739 def formfield(self, **kwargs): 910 defaults = {'form_class': forms.RegexField, 'regex': r'^[a-zA-Z0-9_-]+$', 911 'error_messages': {'invalid': _(u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.")}, 912 } 740 defaults = {'form_class': forms.SlugField} 913 741 defaults.update(kwargs) 914 742 return super(SlugField, self).formfield(**defaults) 915 743 916 744 class SmallIntegerField(IntegerField): 917 def get_manipulator_field_objs(self):918 return [oldforms.SmallIntegerField]919 920 745 def get_internal_type(self): 921 746 return "SmallIntegerField" 922 747 923 748 class TextField(Field): 924 def get_manipulator_field_objs(self):925 return [oldforms.LargeTextField]926 927 749 def get_internal_type(self): 928 750 return "TextField" … … 958 780 usecs = int(usecs) 959 781 except ValueError: 960 raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.') 782 raise exceptions.ValidationError( 783 _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.')) 961 784 else: 962 785 usecs = 0 … … 971 794 **kwargs) 972 795 except ValueError: 973 raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.') 796 raise exceptions.ValidationError( 797 _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.')) 974 798 975 799 def pre_save(self, model_instance, add): … … 985 809 return connection.ops.value_to_db_time(self.to_python(value)) 986 810 987 def get_manipulator_field_objs(self): 988 return [oldforms.TimeField] 989 990 def flatten_data(self,follow, obj = None): 811 def value_to_string(self, obj): 991 812 val = self._get_val_from_obj(obj) 992 return {self.attname: (val is not None and val.strftime("%H:%M:%S") or '')} 813 if val is None: 814 data = '' 815 else: 816 data = val.strftime("%H:%M:%S") 817 return data 993 818 994 819 def formfield(self, **kwargs): … … 1000 825 def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): 1001 826 kwargs['max_length'] = kwargs.get('max_length', 200) 1002 if verify_exists:1003 kwargs.setdefault('validator_list', []).append(validators.isExistingURL)1004 827 self.verify_exists = verify_exists 1005 828 CharField.__init__(self, verbose_name, name, **kwargs) 1006 829 1007 def get_manipulator_field_objs(self):1008 return [oldforms.URLField]1009 1010 830 def formfield(self, **kwargs): 1011 831 defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists} … … 1014 834 1015 835 class USStateField(Field): 1016 def get_manipulator_field_objs(self):1017 return [oldforms.USStateField]1018 1019 836 def get_internal_type(self): 1020 837 return "USStateField" … … 1030 847 self.schema_path = schema_path 1031 848 Field.__init__(self, verbose_name, name, **kwargs) 1032 1033 def get_manipulator_field_objs(self):1034 return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)]1035 django/trunk/django/db/models/fields/related.py
r8571 r8616 5 5 from django.db.models.query import QuerySet 6 6 from django.db.models.query_utils import QueryWrapper 7 from django.utils.encoding import smart_unicode 7 8 from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _ 8 9 from django.utils.functional import curry 9 from django.core import validators 10 from django import oldforms 10 from django.core import exceptions 11 11 from django import forms 12 12 … … 15 15 except NameError: 16 16 from sets import Set as set # Python 2.3 fallback 17 18 # Values for Relation.edit_inline.19 TABULAR, STACKED = 1, 220 17 21 18 RECURSIVE_RELATIONSHIP_CONSTANT = 'self' … … 83 80 84 81 signals.class_prepared.connect(do_pending_lookups) 85 86 def manipulator_valid_rel_key(f, self, field_data, all_data):87 "Validates that the value is a valid foreign key"88 klass = f.rel.to89 try:90 klass._default_manager.get(**{f.rel.field_name: field_data})91 except klass.DoesNotExist:92 raise validators.ValidationError, _("Please enter a valid %s.") % f.verbose_name93 82 94 83 #HACK … … 581 570 582 571 class ManyToOneRel(object): 583 def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None, 584 max_num_in_admin=None, num_extra_on_change=1, edit_inline=False, 585 related_name=None, limit_choices_to=None, lookup_overrides=None, 586 parent_link=False): 572 def __init__(self, to, field_name, related_name=None, 573 limit_choices_to=None, lookup_overrides=None, parent_link=False): 587 574 try: 588 575 to._meta … … 590 577 assert isinstance(to, basestring), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT 591 578 self.to, self.field_name = to, field_name 592 self.num_in_admin, self.edit_inline = num_in_admin, edit_inline 593 self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin 594 self.num_extra_on_change, self.related_name = num_extra_on_change, related_name 579 self.related_name = related_name 595 580 if limit_choices_to is None: 596 581 limit_choices_to = {} … … 612 597 613 598 class OneToOneRel(ManyToOneRel): 614 def __init__(self, to, field_name, num_in_admin=0, min_num_in_admin=None, 615 max_num_in_admin=None, num_extra_on_change=None, edit_inline=False, 616 related_name=None, limit_choices_to=None, lookup_overrides=None, 617 parent_link=False): 618 # NOTE: *_num_in_admin and num_extra_on_change are intentionally 619 # ignored here. We accept them as parameters only to match the calling 620 # signature of ManyToOneRel.__init__(). 621 super(OneToOneRel, self).__init__(to, field_name, num_in_admin, 622 edit_inline=edit_inline, related_name=related_name, 623 limit_choices_to=limit_choices_to, 599 def __init__(self, to, field_name, related_name=None, 600 limit_choices_to=None, lookup_overrides=None, parent_link=False): 601 super(OneToOneRel, self).__init__(to, field_name, 602 related_name=related_name, limit_choices_to=limit_choices_to, 624 603 lookup_overrides=lookup_overrides, parent_link=parent_link) 625 604 self.multiple = False 626 605 627 606 class ManyToManyRel(object): 628 def __init__(self, to, num_in_admin=0, related_name=None,629 limit_choices_to=None,symmetrical=True, through=None):607 def __init__(self, to, related_name=None, limit_choices_to=None, 608 symmetrical=True, through=None): 630 609 self.to = to 631 self.num_in_admin = num_in_admin632 610 self.related_name = related_name 633 611 if limit_choices_to is None: 634 612 limit_choices_to = {} 635 613 self.limit_choices_to = limit_choices_to 636 self.edit_inline = False637 614 self.symmetrical = symmetrical 638 615 self.multiple = True … … 652 629 653 630 kwargs['rel'] = rel_class(to, to_field, 654 num_in_admin=kwargs.pop('num_in_admin', 3),655 min_num_in_admin=kwargs.pop('min_num_in_admin', None),656 max_num_in_admin=kwargs.pop('max_num_in_admin', None),657 num_extra_on_change=kwargs.pop('num_extra_on_change', 1),658 edit_inline=kwargs.pop('edit_inline', False),659 631 related_name=kwargs.pop('related_name', None), 660 632 limit_choices_to=kwargs.pop('limit_choices_to', None), … … 670 642 def get_validator_unique_lookup_type(self): 671 643 return '%s__%s__exact' % (self.name, self.rel.get_related_field().name) 672 673 def prepare_field_objs_and_params(self, manipulator, name_prefix):674 params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname}675 if self.null:676 field_objs = [oldforms.NullSelectField]677 else:678 field_objs = [oldforms.SelectField]679 params['choices'] = self.get_choices_default()680 return field_objs, params681 644 682 645 def get_default(self): … … 687 650 return field_default 688 651 689 def get_manipulator_field_objs(self):690 rel_field = self.rel.get_related_field()691 return [oldforms.IntegerField]692 693 652 def get_db_prep_save(self, value): 694 653 if value == '' or value == None: … … 697 656 return self.rel.get_related_field().get_db_prep_save(value) 698 657 699 def flatten_data(self, follow, obj=None):658 def value_to_string(self, obj): 700 659 if not obj: 701 660 # In required many-to-one fields with only one available choice, … … 706 665 choice_list = self.get_choices_default() 707 666 if len(choice_list) == 2: 708 return {self.attname: choice_list[1][0]}709 return Field. flatten_data(self, follow, obj)667 return smart_unicode(choice_list[1][0]) 668 return Field.value_to_string(self, obj) 710 669 711 670 def contribute_to_class(self, cls, name): … … 745 704 def __init__(self, to, to_field=None, **kwargs): 746 705 kwargs['unique'] = True 747 if 'num_in_admin' not in kwargs:748 kwargs['num_in_admin'] = 0749 706 super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs) 750 707 … … 769 726 kwargs['verbose_name'] = kwargs.get('verbose_name', None) 770 727 kwargs['rel'] = ManyToManyRel(to, 771 num_in_admin=kwargs.pop('num_in_admin', 0),772 728 related_name=kwargs.pop('related_name', None), 773 729 limit_choices_to=kwargs.pop('limit_choices_to', None), … … 786 742 msg = ugettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.') 787 743 self.help_text = string_concat(self.help_text, ' ', msg) 788 789 def get_manipulator_field_objs(self):790 choices = self.get_choices_default()791 return [curry(oldforms.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)]792 744 793 745 def get_choices_default(self): … … 864 816 if len(objects) != len(pks): 865 817 badkeys = [k for k in pks if k not in objects] 866 raise validators.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.", 867 "Please enter valid %(self)s IDs. The values %(value)r are invalid.", len(badkeys)) % { 818 raise exceptions.ValidationError( 819 ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.", 820 "Please enter valid %(self)s IDs. The values %(value)r are invalid.", 821 len(badkeys)) % { 868 822 'self': self.verbose_name, 869 823 'value': len(badkeys) == 1 and badkeys[0] or tuple(badkeys), 870 } 871 872 def flatten_data(self, follow, obj = None):873 new_data = {}824 }) 825 826 def value_to_string(self, obj): 827 data = '' 874 828 if obj: 875 instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()]876 new_data[self.name] = instance_ids829 qs = getattr(obj, self.name).all() 830 data = [instance._get_pk_val() for instance in qs] 877 831 else: 878 832 # In required many-to-many fields with only one available choice, 879 833 # select that one available choice. 880 if not self.blank and not self.rel.edit_inline:834 if not self.blank: 881 835 choices_list = self.get_choices_default() 882 836 if len(choices_list) == 1: 883 new_data[self.name]= [choices_list[0][0]]884 return new_data837 data = [choices_list[0][0]] 838 return smart_unicode(data) 885 839 886 840 def contribute_to_class(self, cls, name): django/trunk/django/db/models/__init__.py
r8244 r8616 1 1 from django.conf import settings 2 2 from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured 3 from django.core import validators4 3 from django.db import connection 5 4 from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models … … 10 9 from django.db.models.fields.subclassing import SubfieldBase 11 10 from django.db.models.fields.files import FileField, ImageField 12 from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel , TABULAR, STACKED11 from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel 13 12 from django.db.models import signals 14 13 django/trunk/django/db/models/options.py
r7967 r8616 397 397 return cache 398 398 399 def get_followed_related_objects(self, follow=None):400 if follow == None:401 follow = self.get_follow()402 return [f for f in self.get_all_related_objects() if follow.get(f.name, None)]403 404 def get_data_holders(self, follow=None):405 if follow == None:406 follow = self.get_follow()407 return [f for f in self.fields + self.many_to_many + self.get_all_related_objects() if follow.get(f.name, None)]408 409 def get_follow(self, override=None):410 follow = {}411 for f in self.fields + self.many_to_many + self.get_all_related_objects():412 if override and f.name in override:413 child_override = override[f.name]414 else:415 child_override = None416 fol = f.get_follow(child_override)417 if fol != None:418 follow[f.name] = fol419 return follow420 421 399 def get_base_chain(self, model): 422 400 """ … … 460 438 self._ordered_objects = objects 461 439 return self._ordered_objects 462 463 def has_field_type(self, field_type, follow=None):464 """465 Returns True if this object's admin form has at least one of the given466 field_type (e.g. FileField).467 """468 # TODO: follow469 if not hasattr(self, '_field_types'):470 self._field_types = {}471 if field_type not in self._field_types:472 try:473 # First check self.fields.474 for f in self.fields:475 if isinstance(f, field_type):476 raise StopIteration477 # Failing that, check related fields.478 for related in self.get_followed_related_objects(follow):479 for f in related.opts.fields:480 if isinstance(f, field_type):481 raise StopIteration482 except StopIteration:483 self._field_types[field_type] = True484 else:485 self._field_types[field_type] = False486 return self._field_types[field_type]django/trunk/django/db/models/related.py
r4698 r8616 16 16 self.opts = model._meta 17 17 self.field = field 18 self.edit_inline = field.rel.edit_inline19 18 self.name = '%s:%s' % (self.opts.app_label, self.opts.module_name) 20 19 self.var_name = self.opts.object_name.lower() 21 22 def flatten_data(self, follow, obj=None):23 new_data = {}24 rel_instances = self.get_list(obj)25 for i, rel_instance in enumerate(rel_instances):26 instance_data = {}27 for f in self.opts.fields + self.opts.many_to_many:28 # TODO: Fix for recursive manipulators.29 fol = follow.get(f.name, None)30 if fol:31 field_data = f.flatten_data(fol, rel_instance)32 for name, value in field_data.items():33 instance_data['%s.%d.%s' % (self.var_name, i, name)] = value34 new_data.update(instance_data)35 return new_data36 37 def extract_data(self, data):38 """39 Pull out the data meant for inline objects of this class,40 i.e. anything starting with our module name.41 """42 return data # TODO43 44 def get_list(self, parent_instance=None):45 "Get the list of this type of object from an instance of the parent class."46 if parent_instance is not None:47 attr = getattr(parent_instance, self.get_accessor_name())48 if self.field.rel.multiple:49 # For many-to-many relationships, return a list of objects50 # corresponding to the xxx_num_in_admin options of the field51 objects = list(attr.all())52 53 count = len(objects) + self.field.rel.num_extra_on_change54 if self.field.rel.min_num_in_admin:55 count = max(count, self.field.rel.min_num_in_admin)56 if self.field.rel.max_num_in_admin:57 count = min(count, self.field.rel.max_num_in_admin)58 59 change = count - len(objects)60 if change > 0:61 return objects + [None] * change62 if change < 0:63 return objects[:change]64 else: # Just right65 return objects66 else:67 # A one-to-one relationship, so just return the single related68 # object69 return [attr]70 else:71 if self.field.rel.min_num_in_admin:72 return [None] * max(self.field.rel.num_in_admin, self.field.rel.min_num_in_admin)73 else:74 return [None] * self.field.rel.num_in_admin75 20 76 21 def get_db_prep_lookup(self, lookup_type, value): 77 22 # Defer to the actual field definition for db prep 78 23 return self.field.get_db_prep_lookup(lookup_type, value) 79 24 80 25 def editable_fields(self): 81 26 "Get the fields in this class that should be edited inline." 82 27 return [f for f in self.opts.fields + self.opts.many_to_many if f.editable and f != self.field] 83 84 def get_follow(self, override=None):85 if isinstance(override, bool):86 if override:87 over = {}88 else:89 return None90 else:91 if override:92 over = override.copy()93 elif self.edit_inline:94 over = {}95 else:96 return None97 98 over[self.field.name] = False99 return self.opts.get_follow(over)100 101 def get_manipulator_fields(self, opts, manipulator, change, follow):102 if self.field.rel.multiple:103 if change:104 attr = getattr(manipulator.original_object, self.get_accessor_name())105 count = attr.count()106 count += self.field.rel.num_extra_on_change107 else:108 count = self.field.rel.num_in_admin109 if self.field.rel.min_num_in_admin:110 count = max(count, self.field.rel.min_num_in_admin)111 if self.field.rel.max_num_in_admin:112 count = min(count, self.field.rel.max_num_in_admin)113 else:114 count = 1115 116 fields = []117 for i in range(count):118 for f in self.opts.fields + self.opts.many_to_many:119 if follow.get(f.name, False):120 prefix = '%s.%d.' % (self.var_name, i)121 fields.extend(f.get_manipulator_fields(self.opts, manipulator, change,122 name_prefix=prefix, rel=True))123 return fields124 28 125 29 def __repr__(self): django/trunk/django/forms/fields.py
r8492 r8616 39 39 'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField', 40 40 'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', 41 'SplitDateTimeField', 'IPAddressField', 'FilePathField', 41 'SplitDateTimeField', 'IPAddressField', 'FilePathField', 'SlugField', 42 42 ) 43 43 … … 836 836 def __init__(self, *args, **kwargs): 837 837 super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs) 838 839 slug_re = re.compile(r'^[-\w]+$') 840 841 class SlugField(RegexField): 842 default_error_messages = { 843 'invalid': _(u"Enter a valid 'slug' consisting of letters, numbers," 844 u" underscores or hyphens."), 845 } 846 847 def __init__(self, *args, **kwargs): 848 super(SlugField, self).__init__(slug_re, *args, **kwargs) django/trunk/docs/howto/custom-model-fields.txt
r8572 r8616 109 109 mean model fields and not :ref:`form fields <ref-forms-fields>`) are subclasses 110 110 of :class:`django.db.models.Field`. Most of the information that Django records 111 about a field is common to all fields -- name, help text, validator lists,112 uniqueness and so forth. Storing all that information is handled by ``Field``. 113 We'll get into the precise details of what ``Field`` can do later on; for now, 114 suffice it to say that everything descends from ``Field`` and then customizes 115 key pieces of theclass behavior.111 about a field is common to all fields -- name, help text, uniqueness and so 112 forth. Storing all that information is handled by ``Field``. We'll get into the 113 precise details of what ``Field`` can do later on; for now, suffice it to say 114 that everything descends from ``Field`` and then customizes key pieces of the 115 class behavior. 116 116 117 117 It's important to realize that a Django field class is not what is stored in … … 211 211 * :attr:`~django.db.models.Field.unique_for_month` 212 212 * :attr:`~django.db.models.Field.unique_for_year` 213 * :attr:`~django.db.models.Field.validator_list`214 213 * :attr:`~django.db.models.Field.choices` 215 214 * :attr:`~django.db.models.Field.help_text` … … 568 567 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 569 568 570 .. method:: flatten_data(self, follow, obj=None) 571 572 .. admonition:: Subject to change 573 574 Although implementing this method is necessary to allow field 575 serialization, the API might change in the future. 576 577 Returns a dictionary, mapping the field's attribute name to a flattened string 578 version of the data. This method has some internal uses that aren't of interest 579 to use here (mostly having to do with forms). For our purposes, it's sufficient 580 to return a one item dictionary that maps the attribute name to a string. 569 .. method:: value_to_string(self, obj) 581 570 582 571 This method is used by the serializers to convert the field into a string for 583 output. You can ignore the input parameters for serialization purposes, although 584 calling :meth:`Field._get_val_from_obj(obj) 585 <django.db.models.Field._get_val_from_obj>` is the best way to get the value to 586 serialize. 587 588 For example, since our ``HandField`` uses strings for its data storage anyway, 589 we can reuse some existing conversion code:: 590 591 class HandField(models.Field): 592 # ... 593 594 def flatten_data(self, follow, obj=None): 572 output. Calling :meth:``Field._get_val_from_obj(obj)`` is the best way to get the 573 value to serialize. For example, since our ``HandField`` uses strings for its 574 data storage anyway, we can reuse some existing conversion code:: 575 576 class HandField(models.Field): 577 # ... 578 579 def value_to_string(self, obj): 595 580 value = self._get_val_from_obj(obj) 596 return {self.attname: self.get_db_prep_value(value)}581 return self.get_db_prep_value(value) 597 582 598 583 Some general advice django/trunk/docs/intro/whatsnext.txt
r8506 r8616 155 155 One low-tech way of taking advantage of the text documentation is by using the 156 156 Unix ``grep`` utility to search for a phrase in all of the documentation. For 157 example, this will show you each mention of the phrase " edit_inline" in any157 example, this will show you each mention of the phrase "max_length" in any 158 158 Django document: 159 159 160 160 .. code-block:: bash 161 161 162 $ grep edit_inline/path/to/django/docs/*.txt162 $ grep max_length /path/to/django/docs/*.txt 163 163 164 164 As HTML, locally django/trunk/docs/ref/forms/fields.txt
r8612 r8616 33 33 ... 34 34 ValidationError: [u'Enter a valid e-mail address.'] 35 36 If you've used Django's old forms/validation framework, take care in noticing37 this ``ValidationError`` is different than the previous ``ValidationError``.38 This one lives at ``django.forms.ValidationError`` rather than39 ``django.core.validators.ValidationError``.40 35 41 36 Core field arguments django/trunk/docs/ref/models/fields.txt
r8568 r8616 146 146 meant for static data that doesn't change much, if ever. 147 147 148 ``core``149 --------150 151 .. attribute:: Field.core152 153 For objects that are edited inline to a related object.154 155 In the Django admin, if all "core" fields in an inline-edited object are156 cleared, the object will be deleted.157 158 It is an error to have an inline-editable relation without at least one159 ``core=True`` field.160 161 Please note that each field marked "core" is treated as a required field by the162 Django admin site. Essentially, this means you should put ``core=True`` on all163 required fields in your related object that is being edited inline.164 165 148 ``db_column`` 166 149 ------------- … … 287 270 288 271 Like :attr:`~Field.unique_for_date` and :attr:`~Field.unique_for_month`. 289 290 ``validator_list``291 ------------------292 293 .. attribute:: Field.validator_list294 295 A list of extra validators to apply to the field. Each should be a callable that296 takes the parameters ``field_data, all_data`` and raises297 :exc:`django.core.validators.ValidationError` for errors.298 272 299 273 .. _model-field-types: … … 914 888 The semantics of one-to-one relationships will be changing soon, so we don't 915 889 recommend you use them. If that doesn't scare you away, however, 916 :class:`OneToOneField` takes the same options that :class:`ForeignKey` does, 917 except for the various :attr:`~ForeignKey.edit_inline`-related options. 890 :class:`OneToOneField` takes the same options that :class:`ForeignKey` does. django/trunk/docs/topics/forms/modelforms.txt
r8506 r8616 68 68 ``PositiveIntegerField`` ``IntegerField`` 69 69 ``PositiveSmallIntegerField`` ``IntegerField`` 70 ``SlugField`` ``RegexField`` accepting only letters, 71 numbers, underscores and hyphens 70 ``SlugField`` ``SlugField`` 72 71 ``SmallIntegerField`` ``IntegerField`` 73 72 ``TextField`` ``CharField`` with ``widget=Textarea`` django/trunk/docs/topics/testing.txt
r8567 r8616 900 900 901 901 ``form`` is the name the ``Form`` instance was given in the template 902 context. Note that this works only for ``forms.Form`` instances, not 903 ``oldforms.Form`` instances. 902 context. 904 903 905 904 ``field`` is the name of the field on the form to check. If ``field`` django/trunk/tests/modeltests/field_subclassing/models.py
r7477 r8616 53 53 return [] 54 54 raise FieldError('Invalid lookup type: %r' % lookup_type) 55 56 def flatten_data(self, follow, obj=None):57 return {self.attname: force_unicode(self._get_val_from_obj(obj))}58 55 59 56 class MyModel(models.Model): django/trunk/tests/modeltests/invalid_models/models.py
r8488 r8616 24 24 25 25 class Clash1(models.Model): 26 src_safe = models.CharField(max_length=10 , core=True)26 src_safe = models.CharField(max_length=10) 27 27 28 28 foreign = models.ForeignKey(Target) … … 30 30 31 31 class Clash2(models.Model): 32 src_safe = models.CharField(max_length=10 , core=True)32 src_safe = models.CharField(max_length=10) 33 33 34 34 foreign_1 = models.ForeignKey(Target, related_name='id') … … 47 47 48 48 class Clash3(models.Model): 49 src_safe = models.CharField(max_length=10 , core=True)49 src_safe = models.CharField(max_length=10) 50 50 51 51 foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt') … … 62 62 63 63 class SelfClashForeign(models.Model): 64 src_safe = models.CharField(max_length=10 , core=True)64 src_safe = models.CharField(max_length=10) 65 65 selfclashforeign = models.CharField(max_length=10) 66 66 django/trunk/tests/modeltests/mutually_referential/models.py
r7158 r8616 8 8 9 9 class Parent(Model): 10 name = CharField(max_length=100 , core=True)10 name = CharField(max_length=100) 11 11 12 12 # Use a simple string for forward declarations. django/trunk/tests/regressiontests/model_fields/tests.py
r8190 r8616 19 19 Traceback (most recent call last): 20 20 ... 21 ValidationError: [u'This value must be a decimal number.']21 ValidationError: This value must be a decimal number. 22 22 23 23 >>> f = DecimalField(max_digits=5, decimal_places=1)
