Django

Code

Changeset 8616

Show
Ignore:
Timestamp:
08/27/08 02:19:44 (10 months ago)
Author:
gwilson
Message:

Removed oldforms, validators, and related code:

  • Removed Manipulator, AutomaticManipulator, and related classes.
  • Removed oldforms specific bits from model fields:
    • Removed validator_list and core arguments from constructors.
    • Removed the methods:
      • get_manipulator_field_names
      • get_manipulator_field_objs
      • get_manipulator_fields
      • get_manipulator_new_data
      • prepare_field_objs_and_params
      • get_follow
    • Renamed flatten_data method to value_to_string for better alignment with its use by the serialization framework, which was the only remaining code using flatten_data.
  • Removed oldforms methods from django.db.models.Options class: get_followed_related_objects, get_data_holders, get_follow, and has_field_type.
  • Removed oldforms-admin specific options from django.db.models.fields.related classes: num_in_admin, min_num_in_admin, max_num_in_admin, num_extra_on_change, and edit_inline.
  • Serialization framework
    • Serializer.get_string_value now calls the model fields' renamed value_to_string methods.
    • Removed a special-casing of models.DateTimeField in core.serializers.base.Serializer.get_string_value that's handled by django.db.models.fields.DateTimeField.value_to_string.
  • Removed django.core.validators:
    • Moved ValidationError exception to django.core.exceptions.
    • For the couple places that were using validators, brought over the necessary code to maintain the same functionality.
  • Introduced a SlugField? form field for validation and to compliment the SlugField? model field (refs #8040).
  • Removed an oldforms-style model creation hack (refs #2160).
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/contrib/admin/util.py

    r8575 r8616  
    8686                        # We don't care about populating deleted_objects now. 
    8787                        continue 
    88                 if related.field.rel.edit_inline or not has_admin: 
     88                if not has_admin: 
    8989                    # Don't display link to edit, because it either has no 
    9090                    # admin or is edited inline. 
     
    102102            for sub_obj in getattr(obj, rel_opts_name).all(): 
    103103                has_related_objs = True 
    104                 if related.field.rel.edit_inline or not has_admin: 
     104                if not has_admin: 
    105105                    # Don't display link to edit, because it either has no 
    106106                    # admin or is edited inline. 
     
    133133        if has_related_objs: 
    134134            for sub_obj in rel_objs.all(): 
    135                 if related.field.rel.edit_inline or not has_admin: 
     135                if not has_admin: 
    136136                    # Don't display link to edit, because it either has no 
    137137                    # admin or is edited inline. 
  • django/trunk/django/contrib/auth/management/commands/createsuperuser.py

    r8046 r8616  
    99from optparse import make_option 
    1010from django.contrib.auth.models import User 
    11 from django.core import validator
     11from django.core import exception
    1212from django.core.management.base import BaseCommand, CommandError 
     13from django.utils.translation import ugettext as _ 
    1314 
    1415RE_VALID_USERNAME = re.compile('\w+$') 
     16EMAIL_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 
     21def is_valid_email(value): 
     22    if not EMAIL_RE.search(value): 
     23        raise exceptions.ValidationError(_('Enter a valid e-mail address.')) 
    1524 
    1625class Command(BaseCommand): 
     
    4049                raise CommandError("Invalid username. Use only letters, digits, and underscores") 
    4150            try: 
    42                 validators.isValidEmail(email, None
    43             except validators.ValidationError: 
     51                is_valid_email(email
     52            except exceptions.ValidationError: 
    4453                raise CommandError("Invalid email address.") 
    4554 
     
    95104                        email = raw_input('E-mail address: ') 
    96105                    try: 
    97                         validators.isValidEmail(email, None
    98                     except validators.ValidationError: 
     106                        is_valid_email(email
     107                    except exceptions.ValidationError: 
    99108                        sys.stderr.write("Error: That e-mail address is invalid.\n") 
    100109                        email = None 
  • django/trunk/django/contrib/auth/models.py

    r8543 r8616  
    11from django.contrib import auth 
    2 from django.core import validators 
    32from django.core.exceptions import ImproperlyConfigured 
    43from django.db import models 
  • django/trunk/django/contrib/comments/forms.py

    r8557 r8616  
    118118        comment = self.cleaned_data["comment"] 
    119119        if settings.COMMENTS_ALLOW_PROFANITIES == False: 
    120             # Logic adapted from django.core.validators; it's not clear if they 
    121             # should be used in newforms or will be deprecated along with the 
    122             # rest of oldforms 
    123120            bad_words = [w for w in settings.PROFANITIES_LIST if w in comment.lower()] 
    124121            if bad_words: 
  • django/trunk/django/contrib/comments/models.py

    r8614 r8616  
    66from django.contrib.sites.models import Site 
    77from django.db import models 
    8 from django.core import urlresolvers, validators 
     8from django.core import urlresolvers 
    99from django.utils.translation import ugettext_lazy as _ 
    1010from django.conf import settings 
  • django/trunk/django/contrib/contenttypes/generic.py

    r8608 r8616  
    33""" 
    44 
    5 from django import oldforms 
    65from django.core.exceptions import ObjectDoesNotExist 
    76from django.db import connection 
     
    109from django.db.models.fields.related import RelatedField, Field, ManyToManyRel 
    1110from django.db.models.loading import get_model 
    12 from django.utils.functional import curry 
    13  
    1411from django.forms import ModelForm 
    1512from django.forms.models import BaseModelFormSet, modelformset_factory, save_instance 
    1613from django.contrib.admin.options import InlineModelAdmin, flatten_fieldsets 
     14from django.utils.encoding import smart_unicode 
    1715 
    1816class GenericForeignKey(object): 
     
    121119        Field.__init__(self, **kwargs) 
    122120 
    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  
    127121    def get_choices_default(self): 
    128122        return Field.get_choices(self, include_blank=False) 
    129123 
    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]) 
    136127 
    137128    def m2m_db_table(self): 
     
    291282        self.related_name = related_name 
    292283        self.limit_choices_to = limit_choices_to or {} 
    293         self.edit_inline = False 
    294284        self.symmetrical = symmetrical 
    295285        self.multiple = True 
     
    301291    ct_field_name = "content_type" 
    302292    ct_fk_field_name = "object_id" 
    303      
     293 
    304294    def __init__(self, data=None, files=None, instance=None, save_as_new=None): 
    305295        opts = self.model._meta 
     
    396386class GenericTabularInline(GenericInlineModelAdmin): 
    397387    template = 'admin/edit_inline/tabular.html' 
    398  
  • django/trunk/django/contrib/flatpages/models.py

    r8292 r8616  
    1 from django.core import validators 
    21from django.db import models 
    32from django.contrib.sites.models import Site 
  • django/trunk/django/contrib/localflavor/jp/forms.py

    r7971 r8616  
    33""" 
    44 
    5 from django.core import validators 
    65from django.forms import ValidationError 
    76from django.utils.translation import ugettext_lazy as _ 
  • django/trunk/django/core/exceptions.py

    r7477 r8616  
    3333    pass 
    3434 
     35class ValidationError(Exception): 
     36    """An error while validating data.""" 
     37    pass 
  • django/trunk/django/core/serializers/base.py

    r8151 r8616  
    5858        Convert a field's value to a string. 
    5959        """ 
    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)) 
    6661 
    6762    def start_serialization(self): 
  • django/trunk/django/db/models/base.py

    r8348 r8616  
    99    from sets import Set as set     # Python 2.3 fallback. 
    1010 
    11 import django.db.models.manipulators    # Imported to register signal handler. 
    12 import django.db.models.manager         # Ditto. 
    13 from django.core import validators 
     11import django.db.models.manager     # Imported to register signal handler. 
    1412from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError 
    1513from django.db.models.fields import AutoField 
     
    321319        # First, try an UPDATE. If that doesn't update anything, do an INSERT. 
    322320        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 
    326322        record_exists = True 
    327323        manager = cls._default_manager 
  • django/trunk/django/db/models/fields/files.py

    r8291 r8616  
    1212from django.utils.encoding import force_unicode, smart_str 
    1313from django.utils.translation import ugettext_lazy, ugettext as _ 
    14 from django import oldforms 
    1514from django import forms 
    16 from django.core import validators 
    1715from django.db.models.loading import cache 
    1816 
     
    127125 
    128126    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'): 
    130128            if arg in kwargs: 
    131129                raise TypeError("'%s' is not a valid argument for %s." % (arg, self.__class__)) 
     
    153151            return None 
    154152        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_names 
    164                         self.other_file_field_name = other_file_field_name 
    165                         self.always_test = True 
    166                     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 = True 
    181                 field_list[0].validator_list.append(v) 
    182                 field_list[0].is_required = field_list[1].is_required = False 
    183  
    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_list 
    191153 
    192154    def contribute_to_class(self, cls, name): 
     
    207169            file.close() 
    208170 
    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' 
    217174        if new_data.get(upload_field_name, False): 
    218175            if rel: 
     
    283240        FileField.__init__(self, verbose_name, name, **kwargs) 
    284241 
    285     def get_manipulator_field_objs(self): 
    286         return [oldforms.ImageUploadField, oldforms.HiddenField] 
    287  
    288242    def formfield(self, **kwargs): 
    289243        defaults = {'form_class': forms.ImageField} 
  • django/trunk/django/db/models/fields/__init__.py

    r8528 r8616  
    22import datetime 
    33import os 
     4import re 
    45import time 
    56try: 
     
    1314from django.dispatch import dispatcher 
    1415from django.conf import settings 
    15 from django.core import validators 
    16 from django import oldforms 
    1716from django import forms 
    18 from django.core.exceptions import ObjectDoesNotExist 
     17from django.core import exceptions 
    1918from django.utils.datastructures import DictWrapper 
    2019from django.utils.functional import curry 
     
    3433class FieldDoesNotExist(Exception): 
    3534    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         return 
    44     if getattr(self, 'original_object', None) and self.original_object._get_pk_val() == old_obj._get_pk_val(): 
    45         return 
    46     raise validators.ValidationError, _("%(optname)s with this %(fieldname)s already exists.") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name} 
    4735 
    4836# A guide to Field parameters: 
     
    7462    def __init__(self, verbose_name=None, name=None, primary_key=False, 
    7563            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): 
    8168        self.name = name 
    8269        self.verbose_name = verbose_name 
     
    8875        if self.empty_strings_allowed and connection.features.interprets_empty_strings_as_nulls: 
    8976            self.null = True 
    90         self.core, self.rel, self.default = core, rel, default 
     77        self.rel = rel 
     78        self.default = default 
    9179        self.editable = editable 
    9280        self.serialize = serialize 
    93         self.validator_list = validator_list or [] 
    9481        self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month 
    9582        self.unique_for_year = unique_for_year 
     
    127114        """ 
    128115        Converts the input value into the expected Python data type, raising 
    129         validators.ValidationError if the data can't be converted. Returns the 
    130         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. 
    131118        """ 
    132119        return value 
     
    253240        return "" 
    254241 
    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_length 
    265  
    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. It 
    277         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 keys 
    300         # are a special case, and fields in a related context should set this 
    301         # 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 rel 
    304  
    305         # BooleanFields (CheckboxFields) are a special case. They don't take 
    306         # 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 fields 
    311         # 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  
    327242    def get_validator_unique_lookup_type(self): 
    328243        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 this 
    333         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 = None 
    340         return val 
    341244 
    342245    def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH): 
     
    367270            return self.get_default() 
    368271 
    369     def flatten_data(self, follow, obj=None): 
     272    def value_to_string(self, obj): 
    370273        """ 
    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. 
    374276        """ 
    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)) 
    382278 
    383279    def bind(self, fieldmapping, original, bound_field_class): 
     
    433329            return int(value) 
    434330        except (TypeError, ValueError): 
    435             raise validators.ValidationError, _("This value must be an integer.") 
     331            raise exceptions.ValidationError( 
     332                _("This value must be an integer.")) 
    436333 
    437334    def get_db_prep_value(self, value): 
     
    439336            return None 
    440337        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 called 
    452         # Not in main change pages 
    453         # ignored in related context 
    454         if not rel: 
    455             return None 
    456         return Field.get_manipulator_new_data(self, new_data, rel) 
    457338 
    458339    def contribute_to_class(self, cls, name): 
     
    479360        if value in ('t', 'True', '1'): return True 
    480361        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.")) 
    482364 
    483365    def get_db_prep_value(self, value): 
     
    486368        return bool(value) 
    487369 
    488     def get_manipulator_field_objs(self): 
    489         return [oldforms.CheckboxField] 
    490  
    491370    def formfield(self, **kwargs): 
    492371        defaults = {'form_class': forms.BooleanField} 
     
    495374 
    496375class CharField(Field): 
    497     def get_manipulator_field_objs(self): 
    498         return [oldforms.TextField] 
    499  
    500376    def get_internal_type(self): 
    501377        return "CharField" 
     
    508384                return value 
    509385            else: 
    510                 raise validators.ValidationError, ugettext_lazy("This field cannot be null.") 
     386                raise exceptions.ValidationError( 
     387                    ugettext_lazy("This field cannot be null.")) 
    511388        return smart_unicode(value) 
    512389 
     
    518395# TODO: Maybe move this into contrib, because it's specialized. 
    519396class CommaSeparatedIntegerField(CharField): 
    520     def get_manipulator_field_objs(self): 
    521         return [oldforms.CommaSeparatedIntegerField] 
     397    pass 
     398 
     399ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$') 
    522400 
    523401class DateField(Field): 
     
    541419        if isinstance(value, datetime.date): 
    542420            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('-')) 
    544430        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) 
    548435 
    549436    def pre_save(self, model_instance, add): 
     
    563450                curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False)) 
    564451 
    565     # Needed because of horrible auto_now[_add] behaviour wrt. editable 
    566     def get_follow(self, override=None): 
    567         if override != None: 
    568             return override 
    569         else: 
    570             return self.editable or self.auto_now or self.auto_now_add 
    571  
    572452    def get_db_prep_lookup(self, lookup_type, value): 
    573453        # For "__month" and "__day" lookups, convert the value to a string so 
     
    581461        return connection.ops.value_to_db_date(self.to_python(value)) 
    582462 
    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): 
    587464        val = self._get_val_from_obj(obj) 
    588465        if val is None: 
     
    590467        else: 
    591468            data = datetime_safe.new_date(val).strftime("%Y-%m-%d") 
    592         return {self.attname: data} 
     469        return data 
    593470 
    594471    def formfield(self, **kwargs): 
     
    617494                usecs = int(usecs) 
    618495            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.')) 
    620498        else: 
    621499            usecs = 0 
     
    634512                                             **kwargs) 
    635513                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.')) 
    637516 
    638517    def get_db_prep_value(self, value): 
     
    640519        return connection.ops.value_to_db_datetime(self.to_python(value)) 
    641520 
    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): 
    661522        val = self._get_val_from_obj(obj) 
    662         date_field, time_field = self.get_manipulator_field_names('') 
    663523        if val is None: 
    664             date_data = time_data = '' 
     524            data = '' 
    665525        else: 
    666526            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 
    670529 
    671530    def formfield(self, **kwargs): 
     
    689548            return decimal.Decimal(value) 
    690549        except decimal.InvalidOperation: 
    691             raise validators.ValidationError( 
     550            raise exceptions.ValidationError( 
    692551                _("This value must be a decimal number.")) 
    693552 
     
    716575                self.max_digits, self.decimal_places) 
    717576 
    718     def get_manipulator_field_objs(self): 
    719         return [curry(oldforms.DecimalField, max_digits=self.max_digits, decimal_places=self.decimal_places)] 
    720  
    721577    def formfield(self, **kwargs): 
    722578        defaults = { 
     
    732588        kwargs['max_length'] = kwargs.get('max_length', 75) 
    733589        CharField.__init__(self, *args, **kwargs) 
    734  
    735     def get_manipulator_field_objs(self): 
    736         return [oldforms.EmailField] 
    737590 
    738591    def formfield(self, **kwargs): 
     
    757610        return super(FilePathField, self).formfield(**defaults) 
    758611 
    759     def get_manipulator_field_objs(self): 
    760         return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)] 
    761  
    762612    def get_internal_type(self): 
    763613        return "FilePathField" 
     
    771621        return float(value) 
    772622 
    773     def get_manipulator_field_objs(self): 
    774         return [oldforms.FloatField] 
    775  
    776623    def get_internal_type(self): 
    777624        return "FloatField" 
     
    788635            return None 
    789636        return int(value) 
    790  
    791     def get_manipulator_field_objs(self): 
    792         return [oldforms.IntegerField] 
    793637 
    794638    def get_internal_type(self): 
     
    801645            return int(value) 
    802646        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 
    805650    def formfield(self, **kwargs): 
    806651        defaults = {'form_class': forms.IntegerField} 
     
    814659        Field.__init__(self, *args, **kwargs) 
    815660 
    816     def get_manipulator_field_objs(self): 
    817         return [oldforms.IPAddressField] 
    818  
    819661    def get_internal_type(self): 
    820662        return "IPAddressField" 
     
    839681        if value in ('t', 'True', '1'): return True 
    840682        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.")) 
    842685 
    843686    def get_db_prep_value(self, value): 
     
    845688            return None 
    846689        return bool(value) 
    847  
    848     def get_manipulator_field_objs(self): 
    849         return [oldforms.NullBooleanField] 
    850690 
    851691    def formfield(self, **kwargs): 
     
    859699 
    860700class PhoneNumberField(Field): 
    861     def get_manipulator_field_objs(self): 
    862         return [oldforms.PhoneNumberField] 
    863  
    864701    def get_internal_type(self): 
    865702        return "PhoneNumberField" 
     
    872709 
    873710class PositiveIntegerField(IntegerField): 
    874     def get_manipulator_field_objs(self): 
    875         return [oldforms.PositiveIntegerField] 
    876  
    877711    def get_internal_type(self): 
    878712        return "PositiveIntegerField" 
     
    884718 
    885719class PositiveSmallIntegerField(IntegerField): 
    886     def get_manipulator_field_objs(self): 
    887         return [oldforms.PositiveSmallIntegerField] 
    888  
    889720    def get_internal_type(self): 
    890721        return "PositiveSmallIntegerField" 
     
    898729    def __init__(self, *args, **kwargs): 
    899730        kwargs['max_length'] = kwargs.get('max_length', 50) 
    900         kwargs.setdefault('validator_list', []).append(validators.isSlug) 
    901731        # Set db_index=True unless it's been set manually. 
    902732        if 'db_index' not in kwargs: 
     
    908738 
    909739    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} 
    913741        defaults.update(kwargs) 
    914742        return super(SlugField, self).formfield(**defaults) 
    915743 
    916744class SmallIntegerField(IntegerField): 
    917     def get_manipulator_field_objs(self): 
    918         return [oldforms.SmallIntegerField] 
    919  
    920745    def get_internal_type(self): 
    921746        return "SmallIntegerField" 
    922747 
    923748class TextField(Field): 
    924     def get_manipulator_field_objs(self): 
    925         return [oldforms.LargeTextField] 
    926  
    927749    def get_internal_type(self): 
    928750        return "TextField" 
     
    958780                usecs = int(usecs) 
    959781            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.')) 
    961784        else: 
    962785            usecs = 0 
     
    971794                                         **kwargs) 
    972795            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.')) 
    974798 
    975799    def pre_save(self, model_instance, add): 
     
    985809        return connection.ops.value_to_db_time(self.to_python(value)) 
    986810 
    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): 
    991812        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 
    993818 
    994819    def formfield(self, **kwargs): 
     
    1000825    def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): 
    1001826        kwargs['max_length'] = kwargs.get('max_length', 200) 
    1002         if verify_exists: 
    1003             kwargs.setdefault('validator_list', []).append(validators.isExistingURL) 
    1004827        self.verify_exists = verify_exists 
    1005828        CharField.__init__(self, verbose_name, name, **kwargs) 
    1006829 
    1007     def get_manipulator_field_objs(self): 
    1008         return [oldforms.URLField] 
    1009  
    1010830    def formfield(self, **kwargs): 
    1011831        defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists} 
     
    1014834 
    1015835class USStateField(Field): 
    1016     def get_manipulator_field_objs(self): 
    1017         return [oldforms.USStateField] 
    1018  
    1019836    def get_internal_type(self): 
    1020837        return "USStateField" 
     
    1030847        self.schema_path = schema_path 
    1031848        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  
    55from django.db.models.query import QuerySet 
    66from django.db.models.query_utils import QueryWrapper 
     7from django.utils.encoding import smart_unicode 
    78from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _ 
    89from django.utils.functional import curry 
    9 from django.core import validators 
    10 from django import oldforms 
     10from django.core import exceptions 
    1111from django import forms 
    1212 
     
    1515except NameError: 
    1616    from sets import Set as set   # Python 2.3 fallback 
    17  
    18 # Values for Relation.edit_inline. 
    19 TABULAR, STACKED = 1, 2 
    2017 
    2118RECURSIVE_RELATIONSHIP_CONSTANT = 'self' 
     
    8380 
    8481signals.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.to 
    89     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_name 
    9382 
    9483#HACK 
     
    581570 
    582571class 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): 
    587574        try: 
    588575            to._meta 
     
    590577            assert isinstance(to, basestring), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT 
    591578        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 
    595580        if limit_choices_to is None: 
    596581            limit_choices_to = {} 
     
    612597 
    613598class 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, 
    624603                lookup_overrides=lookup_overrides, parent_link=parent_link) 
    625604        self.multiple = False 
    626605 
    627606class 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): 
    630609        self.to = to 
    631         self.num_in_admin = num_in_admin 
    632610        self.related_name = related_name 
    633611        if limit_choices_to is None: 
    634612            limit_choices_to = {} 
    635613        self.limit_choices_to = limit_choices_to 
    636         self.edit_inline = False 
    637614        self.symmetrical = symmetrical 
    638615        self.multiple = True 
     
    652629 
    653630        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), 
    659631            related_name=kwargs.pop('related_name', None), 
    660632            limit_choices_to=kwargs.pop('limit_choices_to', None), 
     
    670642    def get_validator_unique_lookup_type(self): 
    671643        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, params 
    681644 
    682645    def get_default(self): 
     
    687650        return field_default 
    688651 
    689     def get_manipulator_field_objs(self): 
    690         rel_field = self.rel.get_related_field() 
    691         return [oldforms.IntegerField] 
    692  
    693652    def get_db_prep_save(self, value): 
    694653        if value == '' or value == None: 
     
    697656            return self.rel.get_related_field().get_db_prep_save(value) 
    698657 
    699     def flatten_data(self, follow, obj=None): 
     658    def value_to_string(self, obj): 
    700659        if not obj: 
    701660            # In required many-to-one fields with only one available choice, 
     
    706665                choice_list = self.get_choices_default() 
    707666                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) 
    710669 
    711670    def contribute_to_class(self, cls, name): 
     
    745704    def __init__(self, to, to_field=None, **kwargs): 
    746705        kwargs['unique'] = True 
    747         if 'num_in_admin' not in kwargs: 
    748             kwargs['num_in_admin'] = 0 
    749706        super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs) 
    750707 
     
    769726        kwargs['verbose_name'] = kwargs.get('verbose_name', None) 
    770727        kwargs['rel'] = ManyToManyRel(to, 
    771             num_in_admin=kwargs.pop('num_in_admin', 0), 
    772728            related_name=kwargs.pop('related_name', None), 
    773729            limit_choices_to=kwargs.pop('limit_choices_to', None), 
     
    786742        msg = ugettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.') 
    787743        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)] 
    792744 
    793745    def get_choices_default(self): 
     
    864816        if len(objects) != len(pks): 
    865817            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)) % { 
    868822                'self': self.verbose_name, 
    869823                '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 = '' 
    874828        if obj: 
    875             instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()] 
    876             new_data[self.name] = instance_ids 
     829            qs = getattr(obj, self.name).all() 
     830            data = [instance._get_pk_val() for instance in qs] 
    877831        else: 
    878832            # In required many-to-many fields with only one available choice, 
    879833            # select that one available choice. 
    880             if not self.blank and not self.rel.edit_inline
     834            if not self.blank
    881835                choices_list = self.get_choices_default() 
    882836                if len(choices_list) == 1: 
    883                     new_data[self.name] = [choices_list[0][0]] 
    884         return new_data 
     837                    data = [choices_list[0][0]] 
     838        return smart_unicode(data) 
    885839 
    886840    def contribute_to_class(self, cls, name): 
  • django/trunk/django/db/models/__init__.py

    r8244 r8616  
    11from django.conf import settings 
    22from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured 
    3 from django.core import validators 
    43from django.db import connection 
    54from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models 
     
    109from django.db.models.fields.subclassing import SubfieldBase 
    1110from django.db.models.fields.files import FileField, ImageField 
    12 from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel, TABULAR, STACKED 
     11from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel 
    1312from django.db.models import signals 
    1413 
  • django/trunk/django/db/models/options.py

    r7967 r8616  
    397397        return cache 
    398398 
    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 = None 
    416             fol = f.get_follow(child_override) 
    417             if fol != None: 
    418                 follow[f.name] = fol 
    419         return follow 
    420  
    421399    def get_base_chain(self, model): 
    422400        """ 
     
    460438            self._ordered_objects = objects 
    461439        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 given 
    466         field_type (e.g. FileField). 
    467         """ 
    468         # TODO: follow 
    469         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 StopIteration 
    477                 # 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 StopIteration 
    482             except StopIteration: 
    483                 self._field_types[field_type] = True 
    484             else: 
    485                 self._field_types[field_type] = False 
    486         return self._field_types[field_type] 
  • django/trunk/django/db/models/related.py

    r4698 r8616  
    1616        self.opts = model._meta 
    1717        self.field = field 
    18         self.edit_inline = field.rel.edit_inline 
    1918        self.name = '%s:%s' % (self.opts.app_label, self.opts.module_name) 
    2019        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)] = value 
    34             new_data.update(instance_data) 
    35         return new_data 
    36  
    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 # TODO 
    43  
    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 objects 
    50                 # corresponding to the xxx_num_in_admin options of the field 
    51                 objects = list(attr.all()) 
    52  
    53                 count = len(objects) + self.field.rel.num_extra_on_change 
    54                 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] * change 
    62                 if change < 0: 
    63                     return objects[:change] 
    64                 else: # Just right 
    65                     return objects 
    66             else: 
    67                 # A one-to-one relationship, so just return the single related 
    68                 # object 
    69                 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_admin 
    7520 
    7621    def get_db_prep_lookup(self, lookup_type, value): 
    7722        # Defer to the actual field definition for db prep 
    7823        return self.field.get_db_prep_lookup(lookup_type, value) 
    79          
     24 
    8025    def editable_fields(self): 
    8126        "Get the fields in this class that should be edited inline." 
    8227        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 None 
    90         else: 
    91             if override: 
    92                 over = override.copy() 
    93             elif self.edit_inline: 
    94                 over = {} 
    95             else: 
    96                 return None 
    97  
    98         over[self.field.name] = False 
    99         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_change 
    107             else: 
    108                 count = self.field.rel.num_in_admin 
    109             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 = 1 
    115  
    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 fields 
    12428 
    12529    def __repr__(self): 
  • django/trunk/django/forms/fields.py

    r8492 r8616  
    3939    'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField', 
    4040    'ComboField', 'MultiValueField', 'FloatField', 'DecimalField', 
    41     'SplitDateTimeField', 'IPAddressField', 'FilePathField', 
     41    'SplitDateTimeField', 'IPAddressField', 'FilePathField', 'SlugField', 
    4242) 
    4343 
     
    836836    def __init__(self, *args, **kwargs): 
    837837        super(IPAddressField, self).__init__(ipv4_re, *args, **kwargs) 
     838 
     839slug_re = re.compile(r'^[-\w]+$') 
     840 
     841class 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  
    109109mean model fields and not :ref:`form fields <ref-forms-fields>`) are subclasses 
    110110of :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 the class behavior. 
     111about a field is common to all fields -- name, help text, uniqueness and so 
     112forth. Storing all that information is handled by ``Field``. We'll get into the 
     113precise details of what ``Field`` can do later on; for now, suffice it to say 
     114that everything descends from ``Field`` and then customizes key pieces of the 
     115class behavior. 
    116116 
    117117It's important to realize that a Django field class is not what is stored in 
     
    211211    * :attr:`~django.db.models.Field.unique_for_month` 
    212212    * :attr:`~django.db.models.Field.unique_for_year` 
    213     * :attr:`~django.db.models.Field.validator_list` 
    214213    * :attr:`~django.db.models.Field.choices` 
    215214    * :attr:`~django.db.models.Field.help_text` 
     
    568567~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
    569568 
    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) 
    581570 
    582571This 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): 
     572output. Calling :meth:``Field._get_val_from_obj(obj)`` is the best way to get the 
     573value to serialize. For example, since our ``HandField`` uses strings for its 
     574data storage anyway, we can reuse some existing conversion code:: 
     575 
     576    class HandField(models.Field): 
     577        # ... 
     578 
     579        def value_to_string(self, obj): 
    595580            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) 
    597582 
    598583Some general advice 
  • django/trunk/docs/intro/whatsnext.txt

    r8506 r8616  
    155155One low-tech way of taking advantage of the text documentation is by using the 
    156156Unix ``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 any 
     157example, this will show you each mention of the phrase "max_length" in any 
    158158Django document: 
    159159 
    160160.. code-block:: bash 
    161161 
    162     $ grep edit_inline /path/to/django/docs/*.txt 
     162    $ grep max_length /path/to/django/docs/*.txt 
    163163     
    164164As HTML, locally 
  • django/trunk/docs/ref/forms/fields.txt

    r8612 r8616  
    3333    ... 
    3434    ValidationError: [u'Enter a valid e-mail address.'] 
    35  
    36 If you've used Django's old forms/validation framework, take care in noticing 
    37 this ``ValidationError`` is different than the previous ``ValidationError``. 
    38 This one lives at ``django.forms.ValidationError`` rather than 
    39 ``django.core.validators.ValidationError``. 
    4035 
    4136Core field arguments 
  • django/trunk/docs/ref/models/fields.txt

    r8568 r8616  
    146146meant for static data that doesn't change much, if ever. 
    147147 
    148 ``core`` 
    149 -------- 
    150  
    151 .. attribute:: Field.core 
    152  
    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 are 
    156 cleared, the object will be deleted. 
    157  
    158 It is an error to have an inline-editable relation without at least one 
    159 ``core=True`` field. 
    160  
    161 Please note that each field marked "core" is treated as a required field by the 
    162 Django admin site. Essentially, this means you should put ``core=True`` on all 
    163 required fields in your related object that is being edited inline. 
    164  
    165148``db_column`` 
    166149------------- 
     
    287270 
    288271Like :attr:`~Field.unique_for_date` and :attr:`~Field.unique_for_month`. 
    289  
    290 ``validator_list`` 
    291 ------------------ 
    292  
    293 .. attribute:: Field.validator_list 
    294  
    295 A list of extra validators to apply to the field. Each should be a callable that 
    296 takes the parameters ``field_data, all_data`` and raises 
    297 :exc:`django.core.validators.ValidationError` for errors. 
    298272 
    299273.. _model-field-types: 
     
    914888The semantics of one-to-one relationships will be changing soon, so we don't 
    915889recommend 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  
    6868    ``PositiveIntegerField``         ``IntegerField`` 
    6969    ``PositiveSmallIntegerField``    ``IntegerField`` 
    70     ``SlugField``                    ``RegexField`` accepting only letters, 
    71                                      numbers, underscores and hyphens 
     70    ``SlugField``                    ``SlugField`` 
    7271    ``SmallIntegerField``            ``IntegerField`` 
    7372    ``TextField``                    ``CharField`` with ``widget=Textarea`` 
  • django/trunk/docs/topics/testing.txt

    r8567 r8616  
    900900 
    901901    ``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. 
    904903 
    905904    ``field`` is the name of the field on the form to check. If ``field`` 
  • django/trunk/tests/modeltests/field_subclassing/models.py

    r7477 r8616  
    5353            return [] 
    5454        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))} 
    5855 
    5956class MyModel(models.Model): 
  • django/trunk/tests/modeltests/invalid_models/models.py

    r8488 r8616  
    2424 
    2525class Clash1(models.Model): 
    26     src_safe = models.CharField(max_length=10, core=True
     26    src_safe = models.CharField(max_length=10
    2727 
    2828    foreign = models.ForeignKey(Target) 
     
    3030 
    3131class Clash2(models.Model): 
    32     src_safe = models.CharField(max_length=10, core=True
     32    src_safe = models.CharField(max_length=10
    3333 
    3434    foreign_1 = models.ForeignKey(Target, related_name='id') 
     
    4747 
    4848class Clash3(models.Model): 
    49     src_safe = models.CharField(max_length=10, core=True
     49    src_safe = models.CharField(max_length=10
    5050 
    5151    foreign_1 = models.ForeignKey(Target2, related_name='foreign_tgt') 
     
    6262 
    6363class SelfClashForeign(models.Model): 
    64     src_safe = models.CharField(max_length=10, core=True
     64    src_safe = models.CharField(max_length=10
    6565    selfclashforeign = models.CharField(max_length=10) 
    6666 
  • django/trunk/tests/modeltests/mutually_referential/models.py

    r7158 r8616  
    88 
    99class Parent(Model): 
    10     name = CharField(max_length=100, core=True
     10    name = CharField(max_length=100
    1111     
    1212    # Use a simple string for forward declarations. 
  • django/trunk/tests/regressiontests/model_fields/tests.py

    r8190 r8616  
    1919Traceback (most recent call last): 
    2020... 
    21 ValidationError: [u'This value must be a decimal number.'] 
     21ValidationError: This value must be a decimal number. 
    2222 
    2323>>> f = DecimalField(max_digits=5, decimal_places=1)