diff options
| author | Gary Wilson Jr <gary.wilson@gmail.com> | 2008-08-27 07:19:44 +0000 |
|---|---|---|
| committer | Gary Wilson Jr <gary.wilson@gmail.com> | 2008-08-27 07:19:44 +0000 |
| commit | c2ba59fc1da5287d6286e2c2aca4083d5bafe056 (patch) | |
| tree | 26c05bc1b845efadd28126adee8f2a3726f09424 /django/db | |
| parent | a1575766604205b3bddf0f05d13ad698c78a7582 (diff) | |
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).
git-svn-id: http://code.djangoproject.com/svn/django/trunk@8616 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/db')
| -rw-r--r-- | django/db/models/__init__.py | 3 | ||||
| -rw-r--r-- | django/db/models/base.py | 8 | ||||
| -rw-r--r-- | django/db/models/fields/__init__.py | 313 | ||||
| -rw-r--r-- | django/db/models/fields/files.py | 54 | ||||
| -rw-r--r-- | django/db/models/fields/related.py | 98 | ||||
| -rw-r--r-- | django/db/models/manipulators.py | 333 | ||||
| -rw-r--r-- | django/db/models/options.py | 47 | ||||
| -rw-r--r-- | django/db/models/related.py | 98 |
8 files changed, 97 insertions, 857 deletions
diff --git a/django/db/models/__init__.py b/django/db/models/__init__.py index cbd685547e..5413133306 100644 --- a/django/db/models/__init__.py +++ b/django/db/models/__init__.py @@ -1,6 +1,5 @@ from django.conf import settings from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured -from django.core import validators from django.db import connection from django.db.models.loading import get_apps, get_app, get_models, get_model, register_models from django.db.models.query import Q @@ -9,7 +8,7 @@ from django.db.models.base import Model from django.db.models.fields import * from django.db.models.fields.subclassing import SubfieldBase from django.db.models.fields.files import FileField, ImageField -from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel, TABULAR, STACKED +from django.db.models.fields.related import ForeignKey, OneToOneField, ManyToManyField, ManyToOneRel, ManyToManyRel, OneToOneRel from django.db.models import signals # Admin stages. diff --git a/django/db/models/base.py b/django/db/models/base.py index 115d82bd4f..66cfb15be7 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -8,9 +8,7 @@ try: except NameError: from sets import Set as set # Python 2.3 fallback. -import django.db.models.manipulators # Imported to register signal handler. -import django.db.models.manager # Ditto. -from django.core import validators +import django.db.models.manager # Imported to register signal handler. from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError from django.db.models.fields import AutoField from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField @@ -320,9 +318,7 @@ class Model(object): # First, try an UPDATE. If that doesn't update anything, do an INSERT. pk_val = self._get_pk_val(meta) - # Note: the comparison with '' is required for compatibility with - # oldforms-style model creation. - pk_set = pk_val is not None and smart_unicode(pk_val) != u'' + pk_set = pk_val is not None record_exists = True manager = cls._default_manager if pk_set: diff --git a/django/db/models/fields/__init__.py b/django/db/models/fields/__init__.py index b8d05671b1..5c21e7db73 100644 --- a/django/db/models/fields/__init__.py +++ b/django/db/models/fields/__init__.py @@ -1,6 +1,7 @@ import copy import datetime import os +import re import time try: import decimal @@ -12,10 +13,8 @@ from django.db.models import signals from django.db.models.query_utils import QueryWrapper from django.dispatch import dispatcher from django.conf import settings -from django.core import validators -from django import oldforms from django import forms -from django.core.exceptions import ObjectDoesNotExist +from django.core import exceptions from django.utils.datastructures import DictWrapper from django.utils.functional import curry from django.utils.itercompat import tee @@ -34,17 +33,6 @@ BLANK_CHOICE_NONE = [("", "None")] class FieldDoesNotExist(Exception): pass -def manipulator_validator_unique(f, opts, self, field_data, all_data): - "Validates that the value is unique for this field." - lookup_type = f.get_validator_unique_lookup_type() - try: - old_obj = self.manager.get(**{lookup_type: field_data}) - except ObjectDoesNotExist: - return - if getattr(self, 'original_object', None) and self.original_object._get_pk_val() == old_obj._get_pk_val(): - return - raise validators.ValidationError, _("%(optname)s with this %(fieldname)s already exists.") % {'optname': capfirst(opts.verbose_name), 'fieldname': f.verbose_name} - # A guide to Field parameters: # # * name: The name of the field specifed in the model. @@ -73,11 +61,10 @@ class Field(object): def __init__(self, verbose_name=None, name=None, primary_key=False, max_length=None, unique=False, blank=False, null=False, - db_index=False, core=False, rel=None, default=NOT_PROVIDED, - editable=True, serialize=True, unique_for_date=None, - unique_for_month=None, unique_for_year=None, validator_list=None, - choices=None, help_text='', db_column=None, db_tablespace=None, - auto_created=False): + db_index=False, rel=None, default=NOT_PROVIDED, editable=True, + serialize=True, unique_for_date=None, unique_for_month=None, + unique_for_year=None, choices=None, help_text='', db_column=None, + db_tablespace=None, auto_created=False): self.name = name self.verbose_name = verbose_name self.primary_key = primary_key @@ -87,10 +74,10 @@ class Field(object): # option whenever '' is a possible value. if self.empty_strings_allowed and connection.features.interprets_empty_strings_as_nulls: self.null = True - self.core, self.rel, self.default = core, rel, default + self.rel = rel + self.default = default self.editable = editable self.serialize = serialize - self.validator_list = validator_list or [] self.unique_for_date, self.unique_for_month = unique_for_date, unique_for_month self.unique_for_year = unique_for_year self._choices = choices or [] @@ -126,8 +113,8 @@ class Field(object): def to_python(self, value): """ Converts the input value into the expected Python data type, raising - validators.ValidationError if the data can't be converted. Returns the - converted value. Subclasses should override this. + django.core.exceptions.ValidationError if the data can't be converted. + Returns the converted value. Subclasses should override this. """ return value @@ -252,93 +239,9 @@ class Field(object): return None return "" - def get_manipulator_field_names(self, name_prefix): - """ - Returns a list of field names that this object adds to the manipulator. - """ - return [name_prefix + self.name] - - def prepare_field_objs_and_params(self, manipulator, name_prefix): - params = {'validator_list': self.validator_list[:]} - if self.max_length and not self.choices: # Don't give SelectFields a max_length parameter. - params['max_length'] = self.max_length - - if self.choices: - field_objs = [oldforms.SelectField] - - params['choices'] = self.get_flatchoices() - else: - field_objs = self.get_manipulator_field_objs() - return (field_objs, params) - - def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): - """ - Returns a list of oldforms.FormField instances for this field. It - calculates the choices at runtime, not at compile time. - - name_prefix is a prefix to prepend to the "field_name" argument. - rel is a boolean specifying whether this field is in a related context. - """ - field_objs, params = self.prepare_field_objs_and_params(manipulator, name_prefix) - - # Add the "unique" validator(s). - for field_name_list in opts.unique_together: - if field_name_list[0] == self.name: - params['validator_list'].append(getattr(manipulator, 'isUnique%s' % '_'.join(field_name_list))) - - # Add the "unique for..." validator(s). - if self.unique_for_date: - params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_date))) - if self.unique_for_month: - params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_month))) - if self.unique_for_year: - params['validator_list'].append(getattr(manipulator, 'isUnique%sFor%s' % (self.name, self.unique_for_year))) - if self.unique and not rel: - params['validator_list'].append(curry(manipulator_validator_unique, self, opts, manipulator)) - - # Only add is_required=True if the field cannot be blank. Primary keys - # are a special case, and fields in a related context should set this - # as False, because they'll be caught by a separate validator -- - # RequiredIfOtherFieldGiven. - params['is_required'] = not self.blank and not self.primary_key and not rel - - # BooleanFields (CheckboxFields) are a special case. They don't take - # is_required. - if isinstance(self, BooleanField): - del params['is_required'] - - # If this field is in a related context, check whether any other fields - # in the related object have core=True. If so, add a validator -- - # RequiredIfOtherFieldsGiven -- to this FormField. - if rel and not self.blank and not isinstance(self, AutoField) and not isinstance(self, FileField): - # First, get the core fields, if any. - core_field_names = [] - for f in opts.fields: - if f.core and f != self: - core_field_names.extend(f.get_manipulator_field_names(name_prefix)) - # Now, if there are any, add the validator to this FormField. - if core_field_names: - params['validator_list'].append(validators.RequiredIfOtherFieldsGiven(core_field_names, ugettext_lazy("This field is required."))) - - # Finally, add the field_names. - field_names = self.get_manipulator_field_names(name_prefix) - return [man(field_name=field_names[i], **params) for i, man in enumerate(field_objs)] - def get_validator_unique_lookup_type(self): return '%s__exact' % self.name - def get_manipulator_new_data(self, new_data, rel=False): - """ - Given the full new_data dictionary (from the manipulator), returns this - field's data. - """ - if rel: - return new_data.get(self.name, [self.get_default()])[0] - val = new_data.get(self.name, self.get_default()) - if not self.empty_strings_allowed and val == '' and self.null: - val = None - return val - def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH): """Returns choices with a default blank choices included, for use as SelectField choices for this field.""" @@ -366,19 +269,12 @@ class Field(object): else: return self.get_default() - def flatten_data(self, follow, obj=None): + def value_to_string(self, obj): """ - Returns a dictionary mapping the field's manipulator field names to its - "flattened" string values for the admin view. obj is the instance to - extract the values from. + Returns a string value of this field from the passed obj. + This is used by the serialization framework. """ - return {self.attname: self._get_val_from_obj(obj)} - - def get_follow(self, override=None): - if override != None: - return override - else: - return self.editable + return smart_unicode(self._get_val_from_obj(obj)) def bind(self, fieldmapping, original, bound_field_class): return bound_field_class(self, fieldmapping, original) @@ -432,29 +328,14 @@ class AutoField(Field): try: return int(value) except (TypeError, ValueError): - raise validators.ValidationError, _("This value must be an integer.") + raise exceptions.ValidationError( + _("This value must be an integer.")) def get_db_prep_value(self, value): if value is None: return None return int(value) - def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): - if not rel: - return [] # Don't add a FormField unless it's in a related context. - return Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow) - - def get_manipulator_field_objs(self): - return [oldforms.HiddenField] - - def get_manipulator_new_data(self, new_data, rel=False): - # Never going to be called - # Not in main change pages - # ignored in related context - if not rel: - return None - return Field.get_manipulator_new_data(self, new_data, rel) - def contribute_to_class(self, cls, name): assert not cls._meta.has_auto_field, "A model can't have more than one AutoField." super(AutoField, self).contribute_to_class(cls, name) @@ -478,25 +359,20 @@ class BooleanField(Field): if value in (True, False): return value if value in ('t', 'True', '1'): return True if value in ('f', 'False', '0'): return False - raise validators.ValidationError, _("This value must be either True or False.") + raise exceptions.ValidationError( + _("This value must be either True or False.")) def get_db_prep_value(self, value): if value is None: return None return bool(value) - def get_manipulator_field_objs(self): - return [oldforms.CheckboxField] - def formfield(self, **kwargs): defaults = {'form_class': forms.BooleanField} defaults.update(kwargs) return super(BooleanField, self).formfield(**defaults) class CharField(Field): - def get_manipulator_field_objs(self): - return [oldforms.TextField] - def get_internal_type(self): return "CharField" @@ -507,7 +383,8 @@ class CharField(Field): if self.null: return value else: - raise validators.ValidationError, ugettext_lazy("This field cannot be null.") + raise exceptions.ValidationError( + ugettext_lazy("This field cannot be null.")) return smart_unicode(value) def formfield(self, **kwargs): @@ -517,8 +394,9 @@ class CharField(Field): # TODO: Maybe move this into contrib, because it's specialized. class CommaSeparatedIntegerField(CharField): - def get_manipulator_field_objs(self): - return [oldforms.CommaSeparatedIntegerField] + pass + +ansi_date_re = re.compile(r'^\d{4}-\d{1,2}-\d{1,2}$') class DateField(Field): empty_strings_allowed = False @@ -540,11 +418,20 @@ class DateField(Field): return value.date() if isinstance(value, datetime.date): return value - validators.isValidANSIDate(value, None) + + if not ansi_date_re.search(value): + raise exceptions.ValidationError( + _('Enter a valid date in YYYY-MM-DD format.')) + # Now that we have the date string in YYYY-MM-DD format, check to make + # sure it's a valid date. + # We could use time.strptime here and catch errors, but datetime.date + # produces much friendlier error messages. + year, month, day = map(int, value.split('-')) try: - return datetime.date(*time.strptime(value, '%Y-%m-%d')[:3]) - except ValueError: - raise validators.ValidationError, _('Enter a valid date in YYYY-MM-DD format.') + return datetime.date(year, month, day) + except ValueError, e: + msg = _('Invalid date: %s') % _(str(e)) + raise exceptions.ValidationError(msg) def pre_save(self, model_instance, add): if self.auto_now or (self.auto_now_add and add): @@ -562,13 +449,6 @@ class DateField(Field): setattr(cls, 'get_previous_by_%s' % self.name, curry(cls._get_next_or_previous_by_FIELD, field=self, is_next=False)) - # Needed because of horrible auto_now[_add] behaviour wrt. editable - def get_follow(self, override=None): - if override != None: - return override - else: - return self.editable or self.auto_now or self.auto_now_add - def get_db_prep_lookup(self, lookup_type, value): # For "__month" and "__day" lookups, convert the value to a string so # the database backend always sees a consistent type. @@ -580,16 +460,13 @@ class DateField(Field): # Casts dates into the format expected by the backend return connection.ops.value_to_db_date(self.to_python(value)) - def get_manipulator_field_objs(self): - return [oldforms.DateField] - - def flatten_data(self, follow, obj=None): + def value_to_string(self, obj): val = self._get_val_from_obj(obj) if val is None: data = '' else: data = datetime_safe.new_date(val).strftime("%Y-%m-%d") - return {self.attname: data} + return data def formfield(self, **kwargs): defaults = {'form_class': forms.DateField} @@ -616,7 +493,8 @@ class DateTimeField(DateField): value, usecs = value.split('.') usecs = int(usecs) except ValueError: - raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.') + raise exceptions.ValidationError( + _('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.')) else: usecs = 0 kwargs = {'microsecond': usecs} @@ -633,40 +511,21 @@ class DateTimeField(DateField): return datetime.datetime(*time.strptime(value, '%Y-%m-%d')[:3], **kwargs) except ValueError: - raise validators.ValidationError, _('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.') + raise exceptions.ValidationError( + _('Enter a valid date/time in YYYY-MM-DD HH:MM[:ss[.uuuuuu]] format.')) def get_db_prep_value(self, value): # Casts dates into the format expected by the backend return connection.ops.value_to_db_datetime(self.to_python(value)) - def get_manipulator_field_objs(self): - return [oldforms.DateField, oldforms.TimeField] - - def get_manipulator_field_names(self, name_prefix): - return [name_prefix + self.name + '_date', name_prefix + self.name + '_time'] - - def get_manipulator_new_data(self, new_data, rel=False): - date_field, time_field = self.get_manipulator_field_names('') - if rel: - d = new_data.get(date_field, [None])[0] - t = new_data.get(time_field, [None])[0] - else: - d = new_data.get(date_field, None) - t = new_data.get(time_field, None) - if d is not None and t is not None: - return datetime.datetime.combine(d, t) - return self.get_default() - - def flatten_data(self,follow, obj = None): + def value_to_string(self, obj): val = self._get_val_from_obj(obj) - date_field, time_field = self.get_manipulator_field_names('') if val is None: - date_data = time_data = '' + data = '' else: d = datetime_safe.new_datetime(val) - date_data = d.strftime('%Y-%m-%d') - time_data = d.strftime('%H:%M:%S') - return {date_field: date_data, time_field: time_data} + data = d.strftime('%Y-%m-%d %H:%M:%S') + return data def formfield(self, **kwargs): defaults = {'form_class': forms.DateTimeField} @@ -688,7 +547,7 @@ class DecimalField(Field): try: return decimal.Decimal(value) except decimal.InvalidOperation: - raise validators.ValidationError( + raise exceptions.ValidationError( _("This value must be a decimal number.")) def _format(self, value): @@ -715,9 +574,6 @@ class DecimalField(Field): return connection.ops.value_to_db_decimal(self.to_python(value), self.max_digits, self.decimal_places) - def get_manipulator_field_objs(self): - return [curry(oldforms.DecimalField, max_digits=self.max_digits, decimal_places=self.decimal_places)] - def formfield(self, **kwargs): defaults = { 'max_digits': self.max_digits, @@ -732,9 +588,6 @@ class EmailField(CharField): kwargs['max_length'] = kwargs.get('max_length', 75) CharField.__init__(self, *args, **kwargs) - def get_manipulator_field_objs(self): - return [oldforms.EmailField] - def formfield(self, **kwargs): defaults = {'form_class': forms.EmailField} defaults.update(kwargs) @@ -756,9 +609,6 @@ class FilePathField(Field): defaults.update(kwargs) return super(FilePathField, self).formfield(**defaults) - def get_manipulator_field_objs(self): - return [curry(oldforms.FilePathField, path=self.path, match=self.match, recursive=self.recursive)] - def get_internal_type(self): return "FilePathField" @@ -770,9 +620,6 @@ class FloatField(Field): return None return float(value) - def get_manipulator_field_objs(self): - return [oldforms.FloatField] - def get_internal_type(self): return "FloatField" @@ -788,9 +635,6 @@ class IntegerField(Field): return None return int(value) - def get_manipulator_field_objs(self): - return [oldforms.IntegerField] - def get_internal_type(self): return "IntegerField" @@ -800,8 +644,9 @@ class IntegerField(Field): try: return int(value) except (TypeError, ValueError): - raise validators.ValidationError, _("This value must be an integer.") - + raise exceptions.ValidationError( + _("This value must be an integer.")) + def formfield(self, **kwargs): defaults = {'form_class': forms.IntegerField} defaults.update(kwargs) @@ -813,9 +658,6 @@ class IPAddressField(Field): kwargs['max_length'] = 15 Field.__init__(self, *args, **kwargs) - def get_manipulator_field_objs(self): - return [oldforms.IPAddressField] - def get_internal_type(self): return "IPAddressField" @@ -838,16 +680,14 @@ class NullBooleanField(Field): if value in ('None'): return None if value in ('t', 'True', '1'): return True if value in ('f', 'False', '0'): return False - raise validators.ValidationError, _("This value must be either None, True or False.") + raise exceptions.ValidationError( + _("This value must be either None, True or False.")) def get_db_prep_value(self, value): if value is None: return None return bool(value) - def get_manipulator_field_objs(self): - return [oldforms.NullBooleanField] - def formfield(self, **kwargs): defaults = { 'form_class': forms.NullBooleanField, @@ -858,9 +698,6 @@ class NullBooleanField(Field): return super(NullBooleanField, self).formfield(**defaults) class PhoneNumberField(Field): - def get_manipulator_field_objs(self): - return [oldforms.PhoneNumberField] - def get_internal_type(self): return "PhoneNumberField" @@ -871,9 +708,6 @@ class PhoneNumberField(Field): return super(PhoneNumberField, self).formfield(**defaults) class PositiveIntegerField(IntegerField): - def get_manipulator_field_objs(self): - return [oldforms.PositiveIntegerField] - def get_internal_type(self): return "PositiveIntegerField" @@ -883,9 +717,6 @@ class PositiveIntegerField(IntegerField): return super(PositiveIntegerField, self).formfield(**defaults) class PositiveSmallIntegerField(IntegerField): - def get_manipulator_field_objs(self): - return [oldforms.PositiveSmallIntegerField] - def get_internal_type(self): return "PositiveSmallIntegerField" @@ -897,7 +728,6 @@ class PositiveSmallIntegerField(IntegerField): class SlugField(CharField): def __init__(self, *args, **kwargs): kwargs['max_length'] = kwargs.get('max_length', 50) - kwargs.setdefault('validator_list', []).append(validators.isSlug) # Set db_index=True unless it's been set manually. if 'db_index' not in kwargs: kwargs['db_index'] = True @@ -907,23 +737,15 @@ class SlugField(CharField): return "SlugField" def formfield(self, **kwargs): - defaults = {'form_class': forms.RegexField, 'regex': r'^[a-zA-Z0-9_-]+$', - 'error_messages': {'invalid': _(u"Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.")}, - } + defaults = {'form_class': forms.SlugField} defaults.update(kwargs) return super(SlugField, self).formfield(**defaults) class SmallIntegerField(IntegerField): - def get_manipulator_field_objs(self): - return [oldforms.SmallIntegerField] - def get_internal_type(self): return "SmallIntegerField" class TextField(Field): - def get_manipulator_field_objs(self): - return [oldforms.LargeTextField] - def get_internal_type(self): return "TextField" @@ -957,7 +779,8 @@ class TimeField(Field): value, usecs = value.split('.') usecs = int(usecs) except ValueError: - raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.') + raise exceptions.ValidationError( + _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.')) else: usecs = 0 kwargs = {'microsecond': usecs} @@ -970,7 +793,8 @@ class TimeField(Field): return datetime.time(*time.strptime(value, '%H:%M')[3:5], **kwargs) except ValueError: - raise validators.ValidationError, _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.') + raise exceptions.ValidationError( + _('Enter a valid time in HH:MM[:ss[.uuuuuu]] format.')) def pre_save(self, model_instance, add): if self.auto_now or (self.auto_now_add and add): @@ -984,12 +808,13 @@ class TimeField(Field): # Casts times into the format expected by the backend return connection.ops.value_to_db_time(self.to_python(value)) - def get_manipulator_field_objs(self): - return [oldforms.TimeField] - - def flatten_data(self,follow, obj = None): + def value_to_string(self, obj): val = self._get_val_from_obj(obj) - return {self.attname: (val is not None and val.strftime("%H:%M:%S") or '')} + if val is None: + data = '' + else: + data = val.strftime("%H:%M:%S") + return data def formfield(self, **kwargs): defaults = {'form_class': forms.TimeField} @@ -999,23 +824,15 @@ class TimeField(Field): class URLField(CharField): def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs): kwargs['max_length'] = kwargs.get('max_length', 200) - if verify_exists: - kwargs.setdefault('validator_list', []).append(validators.isExistingURL) self.verify_exists = verify_exists CharField.__init__(self, verbose_name, name, **kwargs) - def get_manipulator_field_objs(self): - return [oldforms.URLField] - def formfield(self, **kwargs): defaults = {'form_class': forms.URLField, 'verify_exists': self.verify_exists} defaults.update(kwargs) return super(URLField, self).formfield(**defaults) class USStateField(Field): - def get_manipulator_field_objs(self): - return [oldforms.USStateField] - def get_internal_type(self): return "USStateField" @@ -1029,7 +846,3 @@ class XMLField(TextField): def __init__(self, verbose_name=None, name=None, schema_path=None, **kwargs): self.schema_path = schema_path Field.__init__(self, verbose_name, name, **kwargs) - - def get_manipulator_field_objs(self): - return [curry(oldforms.XMLLargeTextField, schema_path=self.schema_path)] - diff --git a/django/db/models/fields/files.py b/django/db/models/fields/files.py index 935dee6162..f83f0cf575 100644 --- a/django/db/models/fields/files.py +++ b/django/db/models/fields/files.py @@ -11,9 +11,7 @@ from django.utils.functional import curry from django.db.models import signals from django.utils.encoding import force_unicode, smart_str from django.utils.translation import ugettext_lazy, ugettext as _ -from django import oldforms from django import forms -from django.core import validators from django.db.models.loading import cache class FieldFile(File): @@ -126,7 +124,7 @@ class FileField(Field): attr_class = FieldFile def __init__(self, verbose_name=None, name=None, upload_to='', storage=None, **kwargs): - for arg in ('core', 'primary_key', 'unique'): + for arg in ('primary_key', 'unique'): if arg in kwargs: raise TypeError("'%s' is not a valid argument for %s." % (arg, self.__class__)) @@ -153,42 +151,6 @@ class FileField(Field): return None return unicode(value) - def get_manipulator_fields(self, opts, manipulator, change, name_prefix='', rel=False, follow=True): - field_list = Field.get_manipulator_fields(self, opts, manipulator, change, name_prefix, rel, follow) - if not self.blank: - if rel: - # This validator makes sure FileFields work in a related context. - class RequiredFileField(object): - def __init__(self, other_field_names, other_file_field_name): - self.other_field_names = other_field_names - self.other_file_field_name = other_file_field_name - self.always_test = True - def __call__(self, field_data, all_data): - if not all_data.get(self.other_file_field_name, False): - c = validators.RequiredIfOtherFieldsGiven(self.other_field_names, ugettext_lazy("This field is required.")) - c(field_data, all_data) - # First, get the core fields, if any. - core_field_names = [] - for f in opts.fields: - if f.core and f != self: - core_field_names.extend(f.get_manipulator_field_names(name_prefix)) - # Now, if there are any, add the validator to this FormField. - if core_field_names: - field_list[0].validator_list.append(RequiredFileField(core_field_names, field_list[1].field_name)) - else: - v = validators.RequiredIfOtherFieldNotGiven(field_list[1].field_name, ugettext_lazy("This field is required.")) - v.always_test = True - field_list[0].validator_list.append(v) - field_list[0].is_required = field_list[1].is_required = False - - # If the raw path is passed in, validate it's under the MEDIA_ROOT. - def isWithinMediaRoot(field_data, all_data): - f = os.path.abspath(os.path.join(settings.MEDIA_ROOT, field_data)) - if not f.startswith(os.path.abspath(os.path.normpath(settings.MEDIA_ROOT))): - raise validators.ValidationError(_("Enter a valid filename.")) - field_list[1].validator_list.append(isWithinMediaRoot) - return field_list - def contribute_to_class(self, cls, name): super(FileField, self).contribute_to_class(cls, name) setattr(cls, self.name, FileDescriptor(self)) @@ -206,14 +168,9 @@ class FileField(Field): # Otherwise, just close the file, so it doesn't tie up resources. file.close() - def get_manipulator_field_objs(self): - return [oldforms.FileUploadField, oldforms.HiddenField] - - def get_manipulator_field_names(self, name_prefix): - return [name_prefix + self.name + '_file', name_prefix + self.name] - - def save_file(self, new_data, new_object, original_object, change, rel, save=True): - upload_field_name = self.get_manipulator_field_names('')[0] + def save_file(self, new_data, new_object, original_object, change, rel, + save=True): + upload_field_name = self.name + '_file' if new_data.get(upload_field_name, False): if rel: file = new_data[upload_field_name][0] @@ -282,9 +239,6 @@ class ImageField(FileField): self.width_field, self.height_field = width_field, height_field FileField.__init__(self, verbose_name, name, **kwargs) - def get_manipulator_field_objs(self): - return [oldforms.ImageUploadField, oldforms.HiddenField] - def formfield(self, **kwargs): defaults = {'form_class': forms.ImageField} defaults.update(kwargs) diff --git a/django/db/models/fields/related.py b/django/db/models/fields/related.py index 7601911f0c..db606e5042 100644 --- a/django/db/models/fields/related.py +++ b/django/db/models/fields/related.py @@ -4,10 +4,10 @@ from django.db.models.fields import AutoField, Field, IntegerField, PositiveInte from django.db.models.related import RelatedObject from django.db.models.query import QuerySet from django.db.models.query_utils import QueryWrapper +from django.utils.encoding import smart_unicode from django.utils.translation import ugettext_lazy, string_concat, ungettext, ugettext as _ from django.utils.functional import curry -from django.core import validators -from django import oldforms +from django.core import exceptions from django import forms try: @@ -15,9 +15,6 @@ try: except NameError: from sets import Set as set # Python 2.3 fallback -# Values for Relation.edit_inline. -TABULAR, STACKED = 1, 2 - RECURSIVE_RELATIONSHIP_CONSTANT = 'self' pending_lookups = {} @@ -83,14 +80,6 @@ def do_pending_lookups(sender, **kwargs): signals.class_prepared.connect(do_pending_lookups) -def manipulator_valid_rel_key(f, self, field_data, all_data): - "Validates that the value is a valid foreign key" - klass = f.rel.to - try: - klass._default_manager.get(**{f.rel.field_name: field_data}) - except klass.DoesNotExist: - raise validators.ValidationError, _("Please enter a valid %s.") % f.verbose_name - #HACK class RelatedField(object): def contribute_to_class(self, cls, name): @@ -580,18 +569,14 @@ class ReverseManyRelatedObjectsDescriptor(object): manager.add(*value) class ManyToOneRel(object): - def __init__(self, to, field_name, num_in_admin=3, min_num_in_admin=None, - max_num_in_admin=None, num_extra_on_change=1, edit_inline=False, - related_name=None, limit_choices_to=None, lookup_overrides=None, - parent_link=False): + def __init__(self, to, field_name, related_name=None, + limit_choices_to=None, lookup_overrides=None, parent_link=False): try: to._meta except AttributeError: # to._meta doesn't exist, so it must be RECURSIVE_RELATIONSHIP_CONSTANT assert isinstance(to, basestring), "'to' must be either a model, a model name or the string %r" % RECURSIVE_RELATIONSHIP_CONSTANT self.to, self.field_name = to, field_name - self.num_in_admin, self.edit_inline = num_in_admin, edit_inline - self.min_num_in_admin, self.max_num_in_admin = min_num_in_admin, max_num_in_admin - self.num_extra_on_change, self.related_name = num_extra_on_change, related_name + self.related_name = related_name if limit_choices_to is None: limit_choices_to = {} self.limit_choices_to = limit_choices_to @@ -611,29 +596,21 @@ class ManyToOneRel(object): return data[0] class OneToOneRel(ManyToOneRel): - def __init__(self, to, field_name, num_in_admin=0, min_num_in_admin=None, - max_num_in_admin=None, num_extra_on_change=None, edit_inline=False, - related_name=None, limit_choices_to=None, lookup_overrides=None, - parent_link=False): - # NOTE: *_num_in_admin and num_extra_on_change are intentionally - # ignored here. We accept them as parameters only to match the calling - # signature of ManyToOneRel.__init__(). - super(OneToOneRel, self).__init__(to, field_name, num_in_admin, - edit_inline=edit_inline, related_name=related_name, - limit_choices_to=limit_choices_to, + def __init__(self, to, field_name, related_name=None, + limit_choices_to=None, lookup_overrides=None, parent_link=False): + super(OneToOneRel, self).__init__(to, field_name, + related_name=related_name, limit_choices_to=limit_choices_to, lookup_overrides=lookup_overrides, parent_link=parent_link) self.multiple = False class ManyToManyRel(object): - def __init__(self, to, num_in_admin=0, related_name=None, - limit_choices_to=None, symmetrical=True, through=None): + def __init__(self, to, related_name=None, limit_choices_to=None, + symmetrical=True, through=None): self.to = to - self.num_in_admin = num_in_admin self.related_name = related_name if limit_choices_to is None: limit_choices_to = {} self.limit_choices_to = limit_choices_to - self.edit_inline = False self.symmetrical = symmetrical self.multiple = True self.through = through @@ -651,11 +628,6 @@ class ForeignKey(RelatedField, Field): kwargs['verbose_name'] = kwargs.get('verbose_name', None) kwargs['rel'] = rel_class(to, to_field, - num_in_admin=kwargs.pop('num_in_admin', 3), - min_num_in_admin=kwargs.pop('min_num_in_admin', None), - max_num_in_admin=kwargs.pop('max_num_in_admin', None), - num_extra_on_change=kwargs.pop('num_extra_on_change', 1), - edit_inline=kwargs.pop('edit_inline', False), related_name=kwargs.pop('related_name', None), limit_choices_to=kwargs.pop('limit_choices_to', None), lookup_overrides=kwargs.pop('lookup_overrides', None), @@ -670,15 +642,6 @@ class ForeignKey(RelatedField, Field): def get_validator_unique_lookup_type(self): return '%s__%s__exact' % (self.name, self.rel.get_related_field().name) - def prepare_field_objs_and_params(self, manipulator, name_prefix): - params = {'validator_list': self.validator_list[:], 'member_name': name_prefix + self.attname} - if self.null: - field_objs = [oldforms.NullSelectField] - else: - field_objs = [oldforms.SelectField] - params['choices'] = self.get_choices_default() - return field_objs, params - def get_default(self): "Here we check if the default value is an object and return the to_field if so." field_default = super(ForeignKey, self).get_default() @@ -686,17 +649,13 @@ class ForeignKey(RelatedField, Field): return getattr(field_default, self.rel.get_related_field().attname) return field_default - def get_manipulator_field_objs(self): - rel_field = self.rel.get_related_field() - return [oldforms.IntegerField] - def get_db_prep_save(self, value): if value == '' or value == None: return None else: return self.rel.get_related_field().get_db_prep_save(value) - def flatten_data(self, follow, obj=None): + def value_to_string(self, obj): if not obj: # In required many-to-one fields with only one available choice, # select that one available choice. Note: For SelectFields @@ -705,8 +664,8 @@ class ForeignKey(RelatedField, Field): if not self.blank and self.choices: choice_list = self.get_choices_default() if len(choice_list) == 2: - return {self.attname: choice_list[1][0]} - return Field.flatten_data(self, follow, obj) + return smart_unicode(choice_list[1][0]) + return Field.value_to_string(self, obj) def contribute_to_class(self, cls, name): super(ForeignKey, self).contribute_to_class(cls, name) @@ -744,8 +703,6 @@ class OneToOneField(ForeignKey): """ def __init__(self, to, to_field=None, **kwargs): kwargs['unique'] = True - if 'num_in_admin' not in kwargs: - kwargs['num_in_admin'] = 0 super(OneToOneField, self).__init__(to, to_field, OneToOneRel, **kwargs) def contribute_to_related_class(self, cls, related): @@ -768,7 +725,6 @@ class ManyToManyField(RelatedField, Field): kwargs['verbose_name'] = kwargs.get('verbose_name', None) kwargs['rel'] = ManyToManyRel(to, - num_in_admin=kwargs.pop('num_in_admin', 0), related_name=kwargs.pop('related_name', None), limit_choices_to=kwargs.pop('limit_choices_to', None), symmetrical=kwargs.pop('symmetrical', True), @@ -786,10 +742,6 @@ class ManyToManyField(RelatedField, Field): msg = ugettext_lazy('Hold down "Control", or "Command" on a Mac, to select more than one.') self.help_text = string_concat(self.help_text, ' ', msg) - def get_manipulator_field_objs(self): - choices = self.get_choices_default() - return [curry(oldforms.SelectMultipleField, size=min(max(len(choices), 5), 15), choices=choices)] - def get_choices_default(self): return Field.get_choices(self, include_blank=False) @@ -863,25 +815,27 @@ class ManyToManyField(RelatedField, Field): objects = mod._default_manager.in_bulk(pks) if len(objects) != len(pks): badkeys = [k for k in pks if k not in objects] - raise validators.ValidationError, ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.", - "Please enter valid %(self)s IDs. The values %(value)r are invalid.", len(badkeys)) % { + raise exceptions.ValidationError( + ungettext("Please enter valid %(self)s IDs. The value %(value)r is invalid.", + "Please enter valid %(self)s IDs. The values %(value)r are invalid.", + len(badkeys)) % { 'self': self.verbose_name, 'value': len(badkeys) == 1 and badkeys[0] or tuple(badkeys), - } + }) - def flatten_data(self, follow, obj = None): - new_data = {} + def value_to_string(self, obj): + data = '' if obj: - instance_ids = [instance._get_pk_val() for instance in getattr(obj, self.name).all()] - new_data[self.name] = instance_ids + qs = getattr(obj, self.name).all() + data = [instance._get_pk_val() for instance in qs] else: # In required many-to-many fields with only one available choice, # select that one available choice. - if not self.blank and not self.rel.edit_inline: + if not self.blank: choices_list = self.get_choices_default() if len(choices_list) == 1: - new_data[self.name] = [choices_list[0][0]] - return new_data + data = [choices_list[0][0]] + return smart_unicode(data) def contribute_to_class(self, cls, name): super(ManyToManyField, self).contribute_to_class(cls, name) diff --git a/django/db/models/manipulators.py b/django/db/models/manipulators.py deleted file mode 100644 index c657d0158b..0000000000 --- a/django/db/models/manipulators.py +++ /dev/null @@ -1,333 +0,0 @@ -from django.core.exceptions import ObjectDoesNotExist -from django import oldforms -from django.core import validators -from django.db.models.fields import AutoField -from django.db.models.fields.files import FileField -from django.db.models import signals -from django.utils.functional import curry -from django.utils.datastructures import DotExpandedDict -from django.utils.text import capfirst -from django.utils.encoding import smart_str -from django.utils.translation import ugettext as _ -from django.utils import datetime_safe - -def add_manipulators(sender, **kwargs): - cls = sender - cls.add_to_class('AddManipulator', AutomaticAddManipulator) - cls.add_to_class('ChangeManipulator', AutomaticChangeManipulator) - -signals.class_prepared.connect(add_manipulators) - -class ManipulatorDescriptor(object): - # This class provides the functionality that makes the default model - # manipulators (AddManipulator and ChangeManipulator) available via the - # model class. - def __init__(self, name, base): - self.man = None # Cache of the manipulator class. - self.name = name - self.base = base - - def __get__(self, instance, model=None): - if instance != None: - raise AttributeError, "Manipulator cannot be accessed via instance" - else: - if not self.man: - # Create a class that inherits from the "Manipulator" class - # given in the model class (if specified) and the automatic - # manipulator. - bases = [self.base] - if hasattr(model, 'Manipulator'): - bases = [model.Manipulator] + bases - self.man = type(self.name, tuple(bases), {}) - self.man._prepare(model) - return self.man - -class AutomaticManipulator(oldforms.Manipulator): - def _prepare(cls, model): - cls.model = model - cls.manager = model._default_manager - cls.opts = model._meta - for field_name_list in cls.opts.unique_together: - setattr(cls, 'isUnique%s' % '_'.join(field_name_list), curry(manipulator_validator_unique_together, field_name_list, cls.opts)) - for f in cls.opts.fields: - if f.unique_for_date: - setattr(cls, 'isUnique%sFor%s' % (f.name, f.unique_for_date), curry(manipulator_validator_unique_for_date, f, cls.opts.get_field(f.unique_for_date), cls.opts, 'date')) - if f.unique_for_month: - setattr(cls, 'isUnique%sFor%s' % (f.name, f.unique_for_month), curry(manipulator_validator_unique_for_date, f, cls.opts.get_field(f.unique_for_month), cls.opts, 'month')) - if f.unique_for_year: - setattr(cls, 'isUnique%sFor%s' % (f.name, f.unique_for_year), curry(manipulator_validator_unique_for_date, f, cls.opts.get_field(f.unique_for_year), cls.opts, 'year')) - _prepare = classmethod(_prepare) - - def contribute_to_class(cls, other_cls, name): - setattr(other_cls, name, ManipulatorDescriptor(name, cls)) - contribute_to_class = classmethod(contribute_to_class) - - def __init__(self, follow=None): - self.follow = self.opts.get_follow(follow) - self.fields = [] - - for f in self.opts.fields + self.opts.many_to_many: - if self.follow.get(f.name, False): - self.fields.extend(f.get_manipulator_fields(self.opts, self, self.change)) - - # Add fields for related objects. - for f in self.opts.get_all_related_objects(): - if self.follow.get(f.name, False): - fol = self.follow[f.name] - self.fields.extend(f.get_manipulator_fields(self.opts, self, self.change, fol)) - - # Add field for ordering. - if self.change and self.opts.get_ordered_objects(): - self.fields.append(oldforms.CommaSeparatedIntegerField(field_name="order_")) - - def save(self, new_data): - # TODO: big cleanup when core fields go -> use recursive manipulators. - params = {} - for f in self.opts.fields: - # Fields with auto_now_add should keep their original value in the change stage. - auto_now_add = self.change and getattr(f, 'auto_now_add', False) - if self.follow.get(f.name, None) and not auto_now_add: - param = f.get_manipulator_new_data(new_data) - else: - if self.change: - param = getattr(self.original_object, f.attname) - else: - param = f.get_default() - params[f.attname] = param - - if self.change: - params[self.opts.pk.attname] = self.obj_key - - # First, create the basic object itself. - new_object = self.model(**params) - - # Now that the object's been created, save any uploaded files. - for f in self.opts.fields: - if isinstance(f, FileField): - f.save_file(new_data, new_object, self.change and self.original_object or None, self.change, rel=False, save=False) - - # Now save the object - new_object.save() - - # Calculate which primary fields have changed. - if self.change: - self.fields_added, self.fields_changed, self.fields_deleted = [], [], [] - for f in self.opts.fields: - if not f.primary_key and smart_str(getattr(self.original_object, f.attname)) != smart_str(getattr(new_object, f.attname)): - self.fields_changed.append(f.verbose_name) - - # Save many-to-many objects. Example: Set sites for a poll. - for f in self.opts.many_to_many: - if self.follow.get(f.name, None): - if not f.rel.edit_inline: - new_vals = new_data.getlist(f.name) - # First, clear the existing values. - rel_manager = getattr(new_object, f.name) - rel_manager.clear() - # Then, set the new values. - for n in new_vals: - rel_manager.add(f.rel.to._default_manager.get(pk=n)) - # TODO: Add to 'fields_changed' - - expanded_data = DotExpandedDict(dict(new_data)) - # Save many-to-one objects. Example: Add the Choice objects for a Poll. - for related in self.opts.get_all_related_objects(): - # Create obj_list, which is a DotExpandedDict such as this: - # [('0', {'id': ['940'], 'choice': ['This is the first choice']}), - # ('1', {'id': ['941'], 'choice': ['This is the second choice']}), - # ('2', {'id': [''], 'choice': ['']})] - child_follow = self.follow.get(related.name, None) - - if child_follow: - obj_list = expanded_data.get(related.var_name, {}).items() - if not obj_list: - continue - - obj_list.sort(lambda x, y: cmp(int(x[0]), int(y[0]))) - - # For each related item... - for _, rel_new_data in obj_list: - - params = {} - - # Keep track of which core=True fields were provided. - # If all core fields were given, the related object will be saved. - # If none of the core fields were given, the object will be deleted. - # If some, but not all, of the fields were given, the validator would - # have caught that. - all_cores_given, all_cores_blank = True, True - - # Get a reference to the old object. We'll use it to compare the - # old to the new, to see which fields have changed. - old_rel_obj = None - if self.change: - if rel_new_data[related.opts.pk.name][0]: - try: - old_rel_obj = getattr(self.original_object, related.get_accessor_name()).get(**{'%s__exact' % related.opts.pk.name: rel_new_data[related.opts.pk.attname][0]}) - except ObjectDoesNotExist: - pass - - for f in related.opts.fields: - if f.core and not isinstance(f, FileField) and f.get_manipulator_new_data(rel_new_data, rel=True) in (None, ''): - all_cores_given = False - elif f.core and not isinstance(f, FileField) and f.get_manipulator_new_data(rel_new_data, rel=True) not in (None, ''): - all_cores_blank = False - # If this field isn't editable, give it the same value it had - # previously, according to the given ID. If the ID wasn't - # given, use a default value. FileFields are also a special - # case, because they'll be dealt with later. - - if f == related.field: - param = getattr(new_object, related.field.rel.get_related_field().attname) - elif (not self.change) and isinstance(f, AutoField): - param = None - elif self.change and (isinstance(f, FileField) or not child_follow.get(f.name, None)): - if old_rel_obj: - param = getattr(old_rel_obj, f.column) - else: - param = f.get_default() - else: - param = f.get_manipulator_new_data(rel_new_data, rel=True) - if param != None: - params[f.attname] = param - - # Create the related item. - new_rel_obj = related.model(**params) - - # If all the core fields were provided (non-empty), save the item. - if all_cores_given: - new_rel_obj.save() - - # Save any uploaded files. - for f in related.opts.fields: - if child_follow.get(f.name, None): - if isinstance(f, FileField) and rel_new_data.get(f.name, False): - f.save_file(rel_new_data, new_rel_obj, self.change and old_rel_obj or None, old_rel_obj is not None, rel=True) - - # Calculate whether any fields have changed. - if self.change: - if not old_rel_obj: # This object didn't exist before. - self.fields_added.append('%s "%s"' % (related.opts.verbose_name, new_rel_obj)) - else: - for f in related.opts.fields: - if not f.primary_key and f != related.field and smart_str(getattr(old_rel_obj, f.attname)) != smart_str(getattr(new_rel_obj, f.attname)): - self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj)) - - # Save many-to-many objects. - for f in related.opts.many_to_many: - if child_follow.get(f.name, None) and not f.rel.edit_inline: - new_value = rel_new_data[f.attname] - setattr(new_rel_obj, f.name, f.rel.to.objects.filter(pk__in=new_value)) - if self.change: - self.fields_changed.append('%s for %s "%s"' % (f.verbose_name, related.opts.verbose_name, new_rel_obj)) - - # If, in the change stage, all of the core fields were blank and - # the primary key (ID) was provided, delete the item. - if self.change and all_cores_blank and old_rel_obj: - new_rel_obj.delete() - self.fields_deleted.append('%s "%s"' % (related.opts.verbose_name, old_rel_obj)) - - # Save the order, if applicable. - if self.change and self.opts.get_ordered_objects(): - order = new_data['order_'] and map(int, new_data['order_'].split(',')) or [] - for rel_opts in self.opts.get_ordered_objects(): - getattr(new_object, 'set_%s_order' % rel_opts.object_name.lower())(order) - return new_object - - def get_related_objects(self): - return self.opts.get_followed_related_objects(self.follow) - - def flatten_data(self): - new_data = {} - obj = self.change and self.original_object or None - for f in self.opts.get_data_holders(self.follow): - fol = self.follow.get(f.name) - new_data.update(f.flatten_data(fol, obj)) - return new_data - -class AutomaticAddManipulator(AutomaticManipulator): - change = False - -class AutomaticChangeManipulator(AutomaticManipulator): - change = True - def __init__(self, obj_key, follow=None): - self.obj_key = obj_key - try: - self.original_object = self.manager.get(pk=obj_key) - except ObjectDoesNotExist: - # If the object doesn't exist, this might be a manipulator for a - # one-to-one related object that hasn't created its subobject yet. - # For example, this might be a Restaurant for a Place that doesn't - # yet have restaurant information. - if self.opts.one_to_one_field: - # Sanity check -- Make sure the "parent" object exists. - # For example, make sure the Place exists for the Restaurant. - # Let the ObjectDoesNotExist exception propagate up. - limit_choices_to = self.opts.one_to_one_field.rel.limit_choices_to - lookup_kwargs = {'%s__exact' % self.opts.one_to_one_field.rel.field_name: obj_key} - self.opts.one_to_one_field.rel.to.get_model_module().complex_filter(limit_choices_to).get(**lookup_kwargs) - params = dict([(f.attname, f.get_default()) for f in self.opts.fields]) - params[self.opts.pk.attname] = obj_key - self.original_object = self.opts.get_model_module().Klass(**params) - else: - raise - super(AutomaticChangeManipulator, self).__init__(follow=follow) - -def manipulator_validator_unique_together(field_name_list, opts, self, field_data, all_data): - from django.db.models.fields.related import ManyToOneRel - from django.utils.text import get_text_list - field_list = [opts.get_field(field_name) for field_name in field_name_list] - if isinstance(field_list[0].rel, ManyToOneRel): - kwargs = {'%s__%s__iexact' % (field_name_list[0], field_list[0].rel.field_name): field_data} - else: - kwargs = {'%s__iexact' % field_name_list[0]: field_data} - for f in field_list[1:]: - # This is really not going to work for fields that have different - # form fields, e.g. DateTime. - # This validation needs to occur after html2python to be effective. - field_val = all_data.get(f.name, None) - if field_val is None: - # This will be caught by another validator, assuming the field - # doesn't have blank=True. - return - if isinstance(f.rel, ManyToOneRel): - kwargs['%s__pk' % f.name] = field_val - else: - kwargs['%s__iexact' % f.name] = field_val - try: - old_obj = self.manager.get(**kwargs) - except ObjectDoesNotExist: - return - if hasattr(self, 'original_object') and self.original_object._get_pk_val() == old_obj._get_pk_val(): - pass - else: - raise validators.ValidationError, _("%(object)s with this %(type)s already exists for the given %(field)s.") % \ - {'object': capfirst(opts.verbose_name), 'type': field_list[0].verbose_name, 'field': get_text_list([f.verbose_name for f in field_list[1:]], _('and'))} - -def manipulator_validator_unique_for_date(from_field, date_field, opts, lookup_type, self, field_data, all_data): - from django.db.models.fields.related import ManyToOneRel - date_str = all_data.get(date_field.get_manipulator_field_names('')[0], None) - date_val = oldforms.DateField.html2python(date_str) - if date_val is None: - return # Date was invalid. This will be caught by another validator. - lookup_kwargs = {'%s__year' % date_field.name: date_val.year} - if isinstance(from_field.rel, ManyToOneRel): - lookup_kwargs['%s__pk' % from_field.name] = field_data - else: - lookup_kwargs['%s__iexact' % from_field.name] = field_data - if lookup_type in ('month', 'date'): - lookup_kwargs['%s__month' % date_field.name] = date_val.month - if lookup_type == 'date': - lookup_kwargs['%s__day' % date_field.name] = date_val.day - try: - old_obj = self.manager.get(**lookup_kwargs) - except ObjectDoesNotExist: - return - else: - if hasattr(self, 'original_object') and self.original_object._get_pk_val() == old_obj._get_pk_val(): - pass - else: - format_string = (lookup_type == 'date') and '%B %d, %Y' or '%B %Y' - date_val = datetime_safe.new_datetime(date_val) - raise validators.ValidationError, "Please enter a different %s. The one you entered is already being used for %s." % \ - (from_field.verbose_name, date_val.strftime(format_string)) diff --git a/django/db/models/options.py b/django/db/models/options.py index ffea6d5082..3648cf0710 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -396,28 +396,6 @@ class Options(object): self._related_many_to_many_cache = cache return cache - def get_followed_related_objects(self, follow=None): - if follow == None: - follow = self.get_follow() - return [f for f in self.get_all_related_objects() if follow.get(f.name, None)] - - def get_data_holders(self, follow=None): - if follow == None: - follow = self.get_follow() - return [f for f in self.fields + self.many_to_many + self.get_all_related_objects() if follow.get(f.name, None)] - - def get_follow(self, override=None): - follow = {} - for f in self.fields + self.many_to_many + self.get_all_related_objects(): - if override and f.name in override: - child_override = override[f.name] - else: - child_override = None - fol = f.get_follow(child_override) - if fol != None: - follow[f.name] = fol - return follow - def get_base_chain(self, model): """ Returns a list of parent classes leading to 'model' (order from closet @@ -459,28 +437,3 @@ class Options(object): # objects.append(opts) self._ordered_objects = objects return self._ordered_objects - - def has_field_type(self, field_type, follow=None): - """ - Returns True if this object's admin form has at least one of the given - field_type (e.g. FileField). - """ - # TODO: follow - if not hasattr(self, '_field_types'): - self._field_types = {} - if field_type not in self._field_types: - try: - # First check self.fields. - for f in self.fields: - if isinstance(f, field_type): - raise StopIteration - # Failing that, check related fields. - for related in self.get_followed_related_objects(follow): - for f in related.opts.fields: - if isinstance(f, field_type): - raise StopIteration - except StopIteration: - self._field_types[field_type] = True - else: - self._field_types[field_type] = False - return self._field_types[field_type] diff --git a/django/db/models/related.py b/django/db/models/related.py index 2c1dc5c516..ff7c787a93 100644 --- a/django/db/models/related.py +++ b/django/db/models/related.py @@ -15,113 +15,17 @@ class RelatedObject(object): self.model = model self.opts = model._meta self.field = field - self.edit_inline = field.rel.edit_inline self.name = '%s:%s' % (self.opts.app_label, self.opts.module_name) self.var_name = self.opts.object_name.lower() - def flatten_data(self, follow, obj=None): - new_data = {} - rel_instances = self.get_list(obj) - for i, rel_instance in enumerate(rel_instances): - instance_data = {} - for f in self.opts.fields + self.opts.many_to_many: - # TODO: Fix for recursive manipulators. - fol = follow.get(f.name, None) - if fol: - field_data = f.flatten_data(fol, rel_instance) - for name, value in field_data.items(): - instance_data['%s.%d.%s' % (self.var_name, i, name)] = value - new_data.update(instance_data) - return new_data - - def extract_data(self, data): - """ - Pull out the data meant for inline objects of this class, - i.e. anything starting with our module name. - """ - return data # TODO - - def get_list(self, parent_instance=None): - "Get the list of this type of object from an instance of the parent class." - if parent_instance is not None: - attr = getattr(parent_instance, self.get_accessor_name()) - if self.field.rel.multiple: - # For many-to-many relationships, return a list of objects - # corresponding to the xxx_num_in_admin options of the field - objects = list(attr.all()) - - count = len(objects) + self.field.rel.num_extra_on_change - if self.field.rel.min_num_in_admin: - count = max(count, self.field.rel.min_num_in_admin) - if self.field.rel.max_num_in_admin: - count = min(count, self.field.rel.max_num_in_admin) - - change = count - len(objects) - if change > 0: - return objects + [None] * change - if change < 0: - return objects[:change] - else: # Just right - return objects - else: - # A one-to-one relationship, so just return the single related - # object - return [attr] - else: - if self.field.rel.min_num_in_admin: - return [None] * max(self.field.rel.num_in_admin, self.field.rel.min_num_in_admin) - else: - return [None] * self.field.rel.num_in_admin - def get_db_prep_lookup(self, lookup_type, value): # Defer to the actual field definition for db prep return self.field.get_db_prep_lookup(lookup_type, value) - + def editable_fields(self): "Get the fields in this class that should be edited inline." return [f for f in self.opts.fields + self.opts.many_to_many if f.editable and f != self.field] - def get_follow(self, override=None): - if isinstance(override, bool): - if override: - over = {} - else: - return None - else: - if override: - over = override.copy() - elif self.edit_inline: - over = {} - else: - return None - - over[self.field.name] = False - return self.opts.get_follow(over) - - def get_manipulator_fields(self, opts, manipulator, change, follow): - if self.field.rel.multiple: - if change: - attr = getattr(manipulator.original_object, self.get_accessor_name()) - count = attr.count() - count += self.field.rel.num_extra_on_change - else: - count = self.field.rel.num_in_admin - if self.field.rel.min_num_in_admin: - count = max(count, self.field.rel.min_num_in_admin) - if self.field.rel.max_num_in_admin: - count = min(count, self.field.rel.max_num_in_admin) - else: - count = 1 - - fields = [] - for i in range(count): - for f in self.opts.fields + self.opts.many_to_many: - if follow.get(f.name, False): - prefix = '%s.%d.' % (self.var_name, i) - fields.extend(f.get_manipulator_fields(self.opts, manipulator, change, - name_prefix=prefix, rel=True)) - return fields - def __repr__(self): return "<RelatedObject: %s related to %s>" % (self.name, self.field.name) |
