web/lib/django/db/models/base.py
author ymh <ymh.work@gmail.com>
Wed, 02 Jun 2010 18:57:35 +0200
changeset 38 77b6da96e6f1
permissions -rw-r--r--
update django
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
38
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     1
import types
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     2
import sys
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     3
import os
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     4
from itertools import izip
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     5
import django.db.models.manager     # Imported to register signal handler.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     6
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError, ValidationError, NON_FIELD_ERRORS
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     7
from django.core import validators
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     8
from django.db.models.fields import AutoField, FieldDoesNotExist
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
     9
from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    10
from django.db.models.query import delete_objects, Q
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    11
from django.db.models.query_utils import CollectedObjects, DeferredAttribute
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    12
from django.db.models.options import Options
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    13
from django.db import connections, router, transaction, DatabaseError, DEFAULT_DB_ALIAS
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    14
from django.db.models import signals
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    15
from django.db.models.loading import register_models, get_model
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    16
from django.utils.translation import ugettext_lazy as _
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    17
import django.utils.copycompat as copy
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    18
from django.utils.functional import curry, update_wrapper
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    19
from django.utils.encoding import smart_str, force_unicode, smart_unicode
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    20
from django.utils.text import get_text_list, capfirst
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    21
from django.conf import settings
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    22
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    23
class ModelBase(type):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    24
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    25
    Metaclass for all models.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    26
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    27
    def __new__(cls, name, bases, attrs):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    28
        super_new = super(ModelBase, cls).__new__
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    29
        parents = [b for b in bases if isinstance(b, ModelBase)]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    30
        if not parents:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    31
            # If this isn't a subclass of Model, don't do anything special.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    32
            return super_new(cls, name, bases, attrs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    33
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    34
        # Create the class.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    35
        module = attrs.pop('__module__')
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    36
        new_class = super_new(cls, name, bases, {'__module__': module})
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    37
        attr_meta = attrs.pop('Meta', None)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    38
        abstract = getattr(attr_meta, 'abstract', False)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    39
        if not attr_meta:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    40
            meta = getattr(new_class, 'Meta', None)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    41
        else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    42
            meta = attr_meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    43
        base_meta = getattr(new_class, '_meta', None)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    44
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    45
        if getattr(meta, 'app_label', None) is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    46
            # Figure out the app_label by looking one level up.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    47
            # For 'django.contrib.sites.models', this would be 'sites'.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    48
            model_module = sys.modules[new_class.__module__]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    49
            kwargs = {"app_label": model_module.__name__.split('.')[-2]}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    50
        else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    51
            kwargs = {}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    52
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    53
        new_class.add_to_class('_meta', Options(meta, **kwargs))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    54
        if not abstract:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    55
            new_class.add_to_class('DoesNotExist', subclass_exception('DoesNotExist',
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    56
                    tuple(x.DoesNotExist
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    57
                            for x in parents if hasattr(x, '_meta') and not x._meta.abstract)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    58
                                    or (ObjectDoesNotExist,), module))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    59
            new_class.add_to_class('MultipleObjectsReturned', subclass_exception('MultipleObjectsReturned',
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    60
                    tuple(x.MultipleObjectsReturned
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    61
                            for x in parents if hasattr(x, '_meta') and not x._meta.abstract)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    62
                                    or (MultipleObjectsReturned,), module))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    63
            if base_meta and not base_meta.abstract:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    64
                # Non-abstract child classes inherit some attributes from their
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    65
                # non-abstract parent (unless an ABC comes before it in the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    66
                # method resolution order).
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    67
                if not hasattr(meta, 'ordering'):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    68
                    new_class._meta.ordering = base_meta.ordering
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    69
                if not hasattr(meta, 'get_latest_by'):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    70
                    new_class._meta.get_latest_by = base_meta.get_latest_by
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    71
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    72
        is_proxy = new_class._meta.proxy
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    73
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    74
        if getattr(new_class, '_default_manager', None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    75
            if not is_proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    76
                # Multi-table inheritance doesn't inherit default manager from
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    77
                # parents.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    78
                new_class._default_manager = None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    79
                new_class._base_manager = None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    80
            else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    81
                # Proxy classes do inherit parent's default manager, if none is
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    82
                # set explicitly.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    83
                new_class._default_manager = new_class._default_manager._copy_to_model(new_class)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    84
                new_class._base_manager = new_class._base_manager._copy_to_model(new_class)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    85
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    86
        # Bail out early if we have already created this class.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    87
        m = get_model(new_class._meta.app_label, name, False)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    88
        if m is not None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    89
            return m
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    90
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    91
        # Add all attributes to the class.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    92
        for obj_name, obj in attrs.items():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    93
            new_class.add_to_class(obj_name, obj)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    94
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    95
        # All the fields of any type declared on this model
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    96
        new_fields = new_class._meta.local_fields + \
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    97
                     new_class._meta.local_many_to_many + \
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    98
                     new_class._meta.virtual_fields
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
    99
        field_names = set([f.name for f in new_fields])
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   100
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   101
        # Basic setup for proxy models.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   102
        if is_proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   103
            base = None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   104
            for parent in [cls for cls in parents if hasattr(cls, '_meta')]:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   105
                if parent._meta.abstract:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   106
                    if parent._meta.fields:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   107
                        raise TypeError("Abstract base class containing model fields not permitted for proxy model '%s'." % name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   108
                    else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   109
                        continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   110
                if base is not None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   111
                    raise TypeError("Proxy model '%s' has more than one non-abstract model base class." % name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   112
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   113
                    base = parent
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   114
            if base is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   115
                    raise TypeError("Proxy model '%s' has no non-abstract model base class." % name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   116
            if (new_class._meta.local_fields or
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   117
                    new_class._meta.local_many_to_many):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   118
                raise FieldError("Proxy model '%s' contains model fields." % name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   119
            while base._meta.proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   120
                base = base._meta.proxy_for_model
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   121
            new_class._meta.setup_proxy(base)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   122
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   123
        # Do the appropriate setup for any model parents.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   124
        o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   125
                if isinstance(f, OneToOneField)])
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   126
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   127
        for base in parents:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   128
            original_base = base
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   129
            if not hasattr(base, '_meta'):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   130
                # Things without _meta aren't functional models, so they're
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   131
                # uninteresting parents.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   132
                continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   133
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   134
            parent_fields = base._meta.local_fields + base._meta.local_many_to_many
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   135
            # Check for clashes between locally declared fields and those
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   136
            # on the base classes (we cannot handle shadowed fields at the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   137
            # moment).
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   138
            for field in parent_fields:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   139
                if field.name in field_names:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   140
                    raise FieldError('Local field %r in class %r clashes '
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   141
                                     'with field of similar name from '
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   142
                                     'base class %r' %
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   143
                                        (field.name, name, base.__name__))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   144
            if not base._meta.abstract:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   145
                # Concrete classes...
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   146
                while base._meta.proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   147
                    # Skip over a proxy class to the "real" base it proxies.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   148
                    base = base._meta.proxy_for_model
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   149
                if base in o2o_map:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   150
                    field = o2o_map[base]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   151
                elif not is_proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   152
                    attr_name = '%s_ptr' % base._meta.module_name
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   153
                    field = OneToOneField(base, name=attr_name,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   154
                            auto_created=True, parent_link=True)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   155
                    new_class.add_to_class(attr_name, field)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   156
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   157
                    field = None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   158
                new_class._meta.parents[base] = field
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   159
            else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   160
                # .. and abstract ones.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   161
                for field in parent_fields:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   162
                    new_class.add_to_class(field.name, copy.deepcopy(field))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   163
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   164
                # Pass any non-abstract parent classes onto child.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   165
                new_class._meta.parents.update(base._meta.parents)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   166
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   167
            # Inherit managers from the abstract base classes.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   168
            new_class.copy_managers(base._meta.abstract_managers)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   169
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   170
            # Proxy models inherit the non-abstract managers from their base,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   171
            # unless they have redefined any of them.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   172
            if is_proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   173
                new_class.copy_managers(original_base._meta.concrete_managers)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   174
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   175
            # Inherit virtual fields (like GenericForeignKey) from the parent
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   176
            # class
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   177
            for field in base._meta.virtual_fields:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   178
                if base._meta.abstract and field.name in field_names:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   179
                    raise FieldError('Local field %r in class %r clashes '\
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   180
                                     'with field of similar name from '\
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   181
                                     'abstract base class %r' % \
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   182
                                        (field.name, name, base.__name__))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   183
                new_class.add_to_class(field.name, copy.deepcopy(field))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   184
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   185
        if abstract:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   186
            # Abstract base models can't be instantiated and don't appear in
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   187
            # the list of models for an app. We do the final setup for them a
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   188
            # little differently from normal models.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   189
            attr_meta.abstract = False
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   190
            new_class.Meta = attr_meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   191
            return new_class
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   192
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   193
        new_class._prepare()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   194
        register_models(new_class._meta.app_label, new_class)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   195
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   196
        # Because of the way imports happen (recursively), we may or may not be
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   197
        # the first time this model tries to register with the framework. There
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   198
        # should only be one class for each model, so we always return the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   199
        # registered version.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   200
        return get_model(new_class._meta.app_label, name, False)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   201
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   202
    def copy_managers(cls, base_managers):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   203
        # This is in-place sorting of an Options attribute, but that's fine.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   204
        base_managers.sort()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   205
        for _, mgr_name, manager in base_managers:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   206
            val = getattr(cls, mgr_name, None)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   207
            if not val or val is manager:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   208
                new_manager = manager._copy_to_model(cls)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   209
                cls.add_to_class(mgr_name, new_manager)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   210
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   211
    def add_to_class(cls, name, value):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   212
        if hasattr(value, 'contribute_to_class'):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   213
            value.contribute_to_class(cls, name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   214
        else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   215
            setattr(cls, name, value)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   216
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   217
    def _prepare(cls):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   218
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   219
        Creates some methods once self._meta has been populated.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   220
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   221
        opts = cls._meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   222
        opts._prepare(cls)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   223
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   224
        if opts.order_with_respect_to:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   225
            cls.get_next_in_order = curry(cls._get_next_or_previous_in_order, is_next=True)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   226
            cls.get_previous_in_order = curry(cls._get_next_or_previous_in_order, is_next=False)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   227
            setattr(opts.order_with_respect_to.rel.to, 'get_%s_order' % cls.__name__.lower(), curry(method_get_order, cls))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   228
            setattr(opts.order_with_respect_to.rel.to, 'set_%s_order' % cls.__name__.lower(), curry(method_set_order, cls))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   229
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   230
        # Give the class a docstring -- its definition.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   231
        if cls.__doc__ is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   232
            cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join([f.attname for f in opts.fields]))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   233
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   234
        if hasattr(cls, 'get_absolute_url'):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   235
            cls.get_absolute_url = update_wrapper(curry(get_absolute_url, opts, cls.get_absolute_url),
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   236
                                                  cls.get_absolute_url)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   237
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   238
        signals.class_prepared.send(sender=cls)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   239
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   240
class ModelState(object):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   241
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   242
    A class for storing instance state
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   243
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   244
    def __init__(self, db=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   245
        self.db = db
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   246
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   247
class Model(object):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   248
    __metaclass__ = ModelBase
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   249
    _deferred = False
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   250
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   251
    def __init__(self, *args, **kwargs):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   252
        signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   253
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   254
        # Set up the storage for instance state
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   255
        self._state = ModelState()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   256
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   257
        # There is a rather weird disparity here; if kwargs, it's set, then args
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   258
        # overrides it. It should be one or the other; don't duplicate the work
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   259
        # The reason for the kwargs check is that standard iterator passes in by
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   260
        # args, and instantiation for iteration is 33% faster.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   261
        args_len = len(args)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   262
        if args_len > len(self._meta.fields):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   263
            # Daft, but matches old exception sans the err msg.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   264
            raise IndexError("Number of args exceeds number of fields")
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   265
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   266
        fields_iter = iter(self._meta.fields)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   267
        if not kwargs:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   268
            # The ordering of the izip calls matter - izip throws StopIteration
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   269
            # when an iter throws it. So if the first iter throws it, the second
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   270
            # is *not* consumed. We rely on this, so don't change the order
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   271
            # without changing the logic.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   272
            for val, field in izip(args, fields_iter):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   273
                setattr(self, field.attname, val)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   274
        else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   275
            # Slower, kwargs-ready version.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   276
            for val, field in izip(args, fields_iter):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   277
                setattr(self, field.attname, val)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   278
                kwargs.pop(field.name, None)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   279
                # Maintain compatibility with existing calls.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   280
                if isinstance(field.rel, ManyToOneRel):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   281
                    kwargs.pop(field.attname, None)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   282
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   283
        # Now we're left with the unprocessed fields that *must* come from
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   284
        # keywords, or default.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   285
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   286
        for field in fields_iter:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   287
            is_related_object = False
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   288
            # This slightly odd construct is so that we can access any
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   289
            # data-descriptor object (DeferredAttribute) without triggering its
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   290
            # __get__ method.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   291
            if (field.attname not in kwargs and
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   292
                    isinstance(self.__class__.__dict__.get(field.attname), DeferredAttribute)):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   293
                # This field will be populated on request.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   294
                continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   295
            if kwargs:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   296
                if isinstance(field.rel, ManyToOneRel):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   297
                    try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   298
                        # Assume object instance was passed in.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   299
                        rel_obj = kwargs.pop(field.name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   300
                        is_related_object = True
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   301
                    except KeyError:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   302
                        try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   303
                            # Object instance wasn't passed in -- must be an ID.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   304
                            val = kwargs.pop(field.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   305
                        except KeyError:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   306
                            val = field.get_default()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   307
                    else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   308
                        # Object instance was passed in. Special case: You can
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   309
                        # pass in "None" for related objects if it's allowed.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   310
                        if rel_obj is None and field.null:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   311
                            val = None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   312
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   313
                    try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   314
                        val = kwargs.pop(field.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   315
                    except KeyError:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   316
                        # This is done with an exception rather than the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   317
                        # default argument on pop because we don't want
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   318
                        # get_default() to be evaluated, and then not used.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   319
                        # Refs #12057.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   320
                        val = field.get_default()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   321
            else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   322
                val = field.get_default()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   323
            if is_related_object:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   324
                # If we are passed a related instance, set it using the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   325
                # field.name instead of field.attname (e.g. "user" instead of
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   326
                # "user_id") so that the object gets properly cached (and type
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   327
                # checked) by the RelatedObjectDescriptor.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   328
                setattr(self, field.name, rel_obj)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   329
            else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   330
                setattr(self, field.attname, val)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   331
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   332
        if kwargs:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   333
            for prop in kwargs.keys():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   334
                try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   335
                    if isinstance(getattr(self.__class__, prop), property):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   336
                        setattr(self, prop, kwargs.pop(prop))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   337
                except AttributeError:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   338
                    pass
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   339
            if kwargs:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   340
                raise TypeError("'%s' is an invalid keyword argument for this function" % kwargs.keys()[0])
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   341
        signals.post_init.send(sender=self.__class__, instance=self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   342
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   343
    def __repr__(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   344
        try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   345
            u = unicode(self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   346
        except (UnicodeEncodeError, UnicodeDecodeError):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   347
            u = '[Bad Unicode data]'
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   348
        return smart_str(u'<%s: %s>' % (self.__class__.__name__, u))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   349
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   350
    def __str__(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   351
        if hasattr(self, '__unicode__'):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   352
            return force_unicode(self).encode('utf-8')
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   353
        return '%s object' % self.__class__.__name__
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   354
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   355
    def __eq__(self, other):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   356
        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   357
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   358
    def __ne__(self, other):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   359
        return not self.__eq__(other)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   360
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   361
    def __hash__(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   362
        return hash(self._get_pk_val())
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   363
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   364
    def __reduce__(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   365
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   366
        Provide pickling support. Normally, this just dispatches to Python's
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   367
        standard handling. However, for models with deferred field loading, we
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   368
        need to do things manually, as they're dynamically created classes and
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   369
        only module-level classes can be pickled by the default path.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   370
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   371
        data = self.__dict__
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   372
        model = self.__class__
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   373
        # The obvious thing to do here is to invoke super().__reduce__()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   374
        # for the non-deferred case. Don't do that.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   375
        # On Python 2.4, there is something wierd with __reduce__,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   376
        # and as a result, the super call will cause an infinite recursion.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   377
        # See #10547 and #12121.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   378
        defers = []
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   379
        pk_val = None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   380
        if self._deferred:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   381
            from django.db.models.query_utils import deferred_class_factory
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   382
            factory = deferred_class_factory
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   383
            for field in self._meta.fields:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   384
                if isinstance(self.__class__.__dict__.get(field.attname),
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   385
                        DeferredAttribute):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   386
                    defers.append(field.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   387
                    if pk_val is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   388
                        # The pk_val and model values are the same for all
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   389
                        # DeferredAttribute classes, so we only need to do this
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   390
                        # once.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   391
                        obj = self.__class__.__dict__[field.attname]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   392
                        model = obj.model_ref()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   393
        else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   394
            factory = simple_class_factory
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   395
        return (model_unpickle, (model, defers, factory), data)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   396
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   397
    def _get_pk_val(self, meta=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   398
        if not meta:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   399
            meta = self._meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   400
        return getattr(self, meta.pk.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   401
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   402
    def _set_pk_val(self, value):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   403
        return setattr(self, self._meta.pk.attname, value)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   404
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   405
    pk = property(_get_pk_val, _set_pk_val)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   406
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   407
    def serializable_value(self, field_name):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   408
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   409
        Returns the value of the field name for this instance. If the field is
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   410
        a foreign key, returns the id value, instead of the object. If there's
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   411
        no Field object with this name on the model, the model attribute's
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   412
        value is returned directly.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   413
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   414
        Used to serialize a field's value (in the serializer, or form output,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   415
        for example). Normally, you would just access the attribute directly
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   416
        and not use this method.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   417
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   418
        try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   419
            field = self._meta.get_field_by_name(field_name)[0]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   420
        except FieldDoesNotExist:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   421
            return getattr(self, field_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   422
        return getattr(self, field.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   423
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   424
    def save(self, force_insert=False, force_update=False, using=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   425
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   426
        Saves the current instance. Override this in a subclass if you want to
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   427
        control the saving process.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   428
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   429
        The 'force_insert' and 'force_update' parameters can be used to insist
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   430
        that the "save" must be an SQL insert or update (or equivalent for
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   431
        non-SQL backends), respectively. Normally, they should not be set.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   432
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   433
        if force_insert and force_update:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   434
            raise ValueError("Cannot force both insert and updating in model saving.")
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   435
        self.save_base(using=using, force_insert=force_insert, force_update=force_update)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   436
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   437
    save.alters_data = True
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   438
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   439
    def save_base(self, raw=False, cls=None, origin=None, force_insert=False,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   440
            force_update=False, using=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   441
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   442
        Does the heavy-lifting involved in saving. Subclasses shouldn't need to
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   443
        override this method. It's separate from save() in order to hide the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   444
        need for overrides of save() to pass around internal-only parameters
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   445
        ('raw', 'cls', and 'origin').
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   446
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   447
        using = using or router.db_for_write(self.__class__, instance=self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   448
        connection = connections[using]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   449
        assert not (force_insert and force_update)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   450
        if cls is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   451
            cls = self.__class__
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   452
            meta = cls._meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   453
            if not meta.proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   454
                origin = cls
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   455
        else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   456
            meta = cls._meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   457
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   458
        if origin and not meta.auto_created:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   459
            signals.pre_save.send(sender=origin, instance=self, raw=raw)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   460
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   461
        # If we are in a raw save, save the object exactly as presented.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   462
        # That means that we don't try to be smart about saving attributes
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   463
        # that might have come from the parent class - we just save the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   464
        # attributes we have been given to the class we have been given.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   465
        # We also go through this process to defer the save of proxy objects
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   466
        # to their actual underlying model.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   467
        if not raw or meta.proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   468
            if meta.proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   469
                org = cls
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   470
            else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   471
                org = None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   472
            for parent, field in meta.parents.items():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   473
                # At this point, parent's primary key field may be unknown
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   474
                # (for example, from administration form which doesn't fill
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   475
                # this field). If so, fill it.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   476
                if field and getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   477
                    setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   478
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   479
                self.save_base(cls=parent, origin=org, using=using)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   480
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   481
                if field:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   482
                    setattr(self, field.attname, self._get_pk_val(parent._meta))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   483
            if meta.proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   484
                return
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   485
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   486
        if not meta.proxy:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   487
            non_pks = [f for f in meta.local_fields if not f.primary_key]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   488
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   489
            # First, try an UPDATE. If that doesn't update anything, do an INSERT.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   490
            pk_val = self._get_pk_val(meta)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   491
            pk_set = pk_val is not None
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   492
            record_exists = True
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   493
            manager = cls._base_manager
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   494
            if pk_set:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   495
                # Determine whether a record with the primary key already exists.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   496
                if (force_update or (not force_insert and
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   497
                        manager.using(using).filter(pk=pk_val).exists())):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   498
                    # It does already exist, so do an UPDATE.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   499
                    if force_update or non_pks:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   500
                        values = [(f, None, (raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   501
                        rows = manager.using(using).filter(pk=pk_val)._update(values)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   502
                        if force_update and not rows:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   503
                            raise DatabaseError("Forced update did not affect any rows.")
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   504
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   505
                    record_exists = False
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   506
            if not pk_set or not record_exists:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   507
                if meta.order_with_respect_to:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   508
                    # If this is a model with an order_with_respect_to
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   509
                    # autopopulate the _order field
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   510
                    field = meta.order_with_respect_to
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   511
                    order_value = manager.using(using).filter(**{field.name: getattr(self, field.attname)}).count()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   512
                    setattr(self, '_order', order_value)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   513
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   514
                if not pk_set:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   515
                    if force_update:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   516
                        raise ValueError("Cannot force an update in save() with no primary key.")
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   517
                    values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True), connection=connection))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   518
                        for f in meta.local_fields if not isinstance(f, AutoField)]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   519
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   520
                    values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True), connection=connection))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   521
                        for f in meta.local_fields]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   522
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   523
                record_exists = False
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   524
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   525
                update_pk = bool(meta.has_auto_field and not pk_set)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   526
                if values:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   527
                    # Create a new record.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   528
                    result = manager._insert(values, return_id=update_pk, using=using)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   529
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   530
                    # Create a new record with defaults for everything.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   531
                    result = manager._insert([(meta.pk, connection.ops.pk_default_value())], return_id=update_pk, raw_values=True, using=using)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   532
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   533
                if update_pk:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   534
                    setattr(self, meta.pk.attname, result)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   535
            transaction.commit_unless_managed(using=using)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   536
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   537
        # Store the database on which the object was saved
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   538
        self._state.db = using
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   539
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   540
        # Signal that the save is complete
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   541
        if origin and not meta.auto_created:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   542
            signals.post_save.send(sender=origin, instance=self,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   543
                created=(not record_exists), raw=raw)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   544
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   545
    save_base.alters_data = True
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   546
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   547
    def _collect_sub_objects(self, seen_objs, parent=None, nullable=False):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   548
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   549
        Recursively populates seen_objs with all objects related to this
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   550
        object.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   551
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   552
        When done, seen_objs.items() will be in the format:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   553
            [(model_class, {pk_val: obj, pk_val: obj, ...}),
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   554
             (model_class, {pk_val: obj, pk_val: obj, ...}), ...]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   555
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   556
        pk_val = self._get_pk_val()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   557
        if seen_objs.add(self.__class__, pk_val, self,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   558
                         type(parent), parent, nullable):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   559
            return
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   560
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   561
        for related in self._meta.get_all_related_objects():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   562
            rel_opts_name = related.get_accessor_name()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   563
            if not related.field.rel.multiple:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   564
                try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   565
                    sub_obj = getattr(self, rel_opts_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   566
                except ObjectDoesNotExist:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   567
                    pass
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   568
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   569
                    sub_obj._collect_sub_objects(seen_objs, self, related.field.null)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   570
            else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   571
                # To make sure we can access all elements, we can't use the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   572
                # normal manager on the related object. So we work directly
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   573
                # with the descriptor object.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   574
                for cls in self.__class__.mro():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   575
                    if rel_opts_name in cls.__dict__:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   576
                        rel_descriptor = cls.__dict__[rel_opts_name]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   577
                        break
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   578
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   579
                    # in the case of a hidden fkey just skip it, it'll get
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   580
                    # processed as an m2m
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   581
                    if not related.field.rel.is_hidden():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   582
                        raise AssertionError("Should never get here.")
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   583
                    else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   584
                        continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   585
                delete_qs = rel_descriptor.delete_manager(self).all()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   586
                for sub_obj in delete_qs:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   587
                    sub_obj._collect_sub_objects(seen_objs, self, related.field.null)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   588
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   589
        for related in self._meta.get_all_related_many_to_many_objects():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   590
            if related.field.rel.through:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   591
                db = router.db_for_write(related.field.rel.through.__class__, instance=self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   592
                opts = related.field.rel.through._meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   593
                reverse_field_name = related.field.m2m_reverse_field_name()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   594
                nullable = opts.get_field(reverse_field_name).null
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   595
                filters = {reverse_field_name: self}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   596
                for sub_obj in related.field.rel.through._base_manager.using(db).filter(**filters):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   597
                    sub_obj._collect_sub_objects(seen_objs, self, nullable)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   598
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   599
        for f in self._meta.many_to_many:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   600
            if f.rel.through:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   601
                db = router.db_for_write(f.rel.through.__class__, instance=self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   602
                opts = f.rel.through._meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   603
                field_name = f.m2m_field_name()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   604
                nullable = opts.get_field(field_name).null
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   605
                filters = {field_name: self}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   606
                for sub_obj in f.rel.through._base_manager.using(db).filter(**filters):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   607
                    sub_obj._collect_sub_objects(seen_objs, self, nullable)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   608
            else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   609
                # m2m-ish but with no through table? GenericRelation: cascade delete
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   610
                for sub_obj in f.value_from_object(self).all():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   611
                    # Generic relations not enforced by db constraints, thus we can set
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   612
                    # nullable=True, order does not matter
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   613
                    sub_obj._collect_sub_objects(seen_objs, self, True)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   614
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   615
        # Handle any ancestors (for the model-inheritance case). We do this by
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   616
        # traversing to the most remote parent classes -- those with no parents
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   617
        # themselves -- and then adding those instances to the collection. That
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   618
        # will include all the child instances down to "self".
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   619
        parent_stack = [p for p in self._meta.parents.values() if p is not None]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   620
        while parent_stack:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   621
            link = parent_stack.pop()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   622
            parent_obj = getattr(self, link.name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   623
            if parent_obj._meta.parents:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   624
                parent_stack.extend(parent_obj._meta.parents.values())
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   625
                continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   626
            # At this point, parent_obj is base class (no ancestor models). So
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   627
            # delete it and all its descendents.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   628
            parent_obj._collect_sub_objects(seen_objs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   629
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   630
    def delete(self, using=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   631
        using = using or router.db_for_write(self.__class__, instance=self)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   632
        assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   633
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   634
        # Find all the objects than need to be deleted.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   635
        seen_objs = CollectedObjects()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   636
        self._collect_sub_objects(seen_objs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   637
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   638
        # Actually delete the objects.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   639
        delete_objects(seen_objs, using)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   640
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   641
    delete.alters_data = True
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   642
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   643
    def _get_FIELD_display(self, field):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   644
        value = getattr(self, field.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   645
        return force_unicode(dict(field.flatchoices).get(value, value), strings_only=True)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   646
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   647
    def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   648
        op = is_next and 'gt' or 'lt'
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   649
        order = not is_next and '-' or ''
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   650
        param = smart_str(getattr(self, field.attname))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   651
        q = Q(**{'%s__%s' % (field.name, op): param})
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   652
        q = q|Q(**{field.name: param, 'pk__%s' % op: self.pk})
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   653
        qs = self.__class__._default_manager.using(self._state.db).filter(**kwargs).filter(q).order_by('%s%s' % (order, field.name), '%spk' % order)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   654
        try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   655
            return qs[0]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   656
        except IndexError:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   657
            raise self.DoesNotExist("%s matching query does not exist." % self.__class__._meta.object_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   658
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   659
    def _get_next_or_previous_in_order(self, is_next):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   660
        cachename = "__%s_order_cache" % is_next
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   661
        if not hasattr(self, cachename):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   662
            op = is_next and 'gt' or 'lt'
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   663
            order = not is_next and '-_order' or '_order'
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   664
            order_field = self._meta.order_with_respect_to
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   665
            obj = self._default_manager.filter(**{
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   666
                order_field.name: getattr(self, order_field.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   667
            }).filter(**{
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   668
                '_order__%s' % op: self._default_manager.values('_order').filter(**{
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   669
                    self._meta.pk.name: self.pk
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   670
                })
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   671
            }).order_by(order)[:1].get()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   672
            setattr(self, cachename, obj)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   673
        return getattr(self, cachename)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   674
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   675
    def prepare_database_save(self, unused):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   676
        return self.pk
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   677
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   678
    def clean(self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   679
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   680
        Hook for doing any extra model-wide validation after clean() has been
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   681
        called on every field by self.clean_fields. Any ValidationError raised
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   682
        by this method will not be associated with a particular field; it will
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   683
        have a special-case association with the field defined by NON_FIELD_ERRORS.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   684
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   685
        pass
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   686
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   687
    def validate_unique(self, exclude=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   688
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   689
        Checks unique constraints on the model and raises ``ValidationError``
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   690
        if any failed.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   691
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   692
        unique_checks, date_checks = self._get_unique_checks(exclude=exclude)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   693
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   694
        errors = self._perform_unique_checks(unique_checks)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   695
        date_errors = self._perform_date_checks(date_checks)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   696
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   697
        for k, v in date_errors.items():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   698
            errors.setdefault(k, []).extend(v)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   699
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   700
        if errors:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   701
            raise ValidationError(errors)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   702
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   703
    def _get_unique_checks(self, exclude=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   704
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   705
        Gather a list of checks to perform. Since validate_unique could be
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   706
        called from a ModelForm, some fields may have been excluded; we can't
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   707
        perform a unique check on a model that is missing fields involved
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   708
        in that check.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   709
        Fields that did not validate should also be exluded, but they need
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   710
        to be passed in via the exclude argument.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   711
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   712
        if exclude is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   713
            exclude = []
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   714
        unique_checks = []
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   715
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   716
        unique_togethers = [(self.__class__, self._meta.unique_together)]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   717
        for parent_class in self._meta.parents.keys():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   718
            if parent_class._meta.unique_together:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   719
                unique_togethers.append((parent_class, parent_class._meta.unique_together))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   720
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   721
        for model_class, unique_together in unique_togethers:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   722
            for check in unique_together:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   723
                for name in check:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   724
                    # If this is an excluded field, don't add this check.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   725
                    if name in exclude:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   726
                        break
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   727
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   728
                    unique_checks.append((model_class, tuple(check)))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   729
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   730
        # These are checks for the unique_for_<date/year/month>.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   731
        date_checks = []
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   732
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   733
        # Gather a list of checks for fields declared as unique and add them to
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   734
        # the list of checks.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   735
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   736
        fields_with_class = [(self.__class__, self._meta.local_fields)]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   737
        for parent_class in self._meta.parents.keys():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   738
            fields_with_class.append((parent_class, parent_class._meta.local_fields))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   739
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   740
        for model_class, fields in fields_with_class:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   741
            for f in fields:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   742
                name = f.name
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   743
                if name in exclude:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   744
                    continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   745
                if f.unique:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   746
                    unique_checks.append((model_class, (name,)))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   747
                if f.unique_for_date:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   748
                    date_checks.append((model_class, 'date', name, f.unique_for_date))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   749
                if f.unique_for_year:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   750
                    date_checks.append((model_class, 'year', name, f.unique_for_year))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   751
                if f.unique_for_month:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   752
                    date_checks.append((model_class, 'month', name, f.unique_for_month))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   753
        return unique_checks, date_checks
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   754
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   755
    def _perform_unique_checks(self, unique_checks):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   756
        errors = {}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   757
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   758
        for model_class, unique_check in unique_checks:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   759
            # Try to look up an existing object with the same values as this
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   760
            # object's values for all the unique field.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   761
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   762
            lookup_kwargs = {}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   763
            for field_name in unique_check:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   764
                f = self._meta.get_field(field_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   765
                lookup_value = getattr(self, f.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   766
                if lookup_value is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   767
                    # no value, skip the lookup
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   768
                    continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   769
                if f.primary_key and not getattr(self, '_adding', False):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   770
                    # no need to check for unique primary key when editing
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   771
                    continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   772
                lookup_kwargs[str(field_name)] = lookup_value
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   773
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   774
            # some fields were skipped, no reason to do the check
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   775
            if len(unique_check) != len(lookup_kwargs.keys()):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   776
                continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   777
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   778
            qs = model_class._default_manager.filter(**lookup_kwargs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   779
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   780
            # Exclude the current object from the query if we are editing an
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   781
            # instance (as opposed to creating a new one)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   782
            if not getattr(self, '_adding', False) and self.pk is not None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   783
                qs = qs.exclude(pk=self.pk)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   784
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   785
            if qs.exists():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   786
                if len(unique_check) == 1:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   787
                    key = unique_check[0]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   788
                else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   789
                    key = NON_FIELD_ERRORS
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   790
                errors.setdefault(key, []).append(self.unique_error_message(model_class, unique_check))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   791
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   792
        return errors
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   793
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   794
    def _perform_date_checks(self, date_checks):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   795
        errors = {}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   796
        for model_class, lookup_type, field, unique_for in date_checks:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   797
            lookup_kwargs = {}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   798
            # there's a ticket to add a date lookup, we can remove this special
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   799
            # case if that makes it's way in
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   800
            date = getattr(self, unique_for)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   801
            if lookup_type == 'date':
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   802
                lookup_kwargs['%s__day' % unique_for] = date.day
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   803
                lookup_kwargs['%s__month' % unique_for] = date.month
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   804
                lookup_kwargs['%s__year' % unique_for] = date.year
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   805
            else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   806
                lookup_kwargs['%s__%s' % (unique_for, lookup_type)] = getattr(date, lookup_type)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   807
            lookup_kwargs[field] = getattr(self, field)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   808
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   809
            qs = model_class._default_manager.filter(**lookup_kwargs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   810
            # Exclude the current object from the query if we are editing an
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   811
            # instance (as opposed to creating a new one)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   812
            if not getattr(self, '_adding', False) and self.pk is not None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   813
                qs = qs.exclude(pk=self.pk)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   814
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   815
            if qs.exists():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   816
                errors.setdefault(field, []).append(
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   817
                    self.date_error_message(lookup_type, field, unique_for)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   818
                )
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   819
        return errors
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   820
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   821
    def date_error_message(self, lookup_type, field, unique_for):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   822
        opts = self._meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   823
        return _(u"%(field_name)s must be unique for %(date_field)s %(lookup)s.") % {
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   824
            'field_name': unicode(capfirst(opts.get_field(field).verbose_name)),
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   825
            'date_field': unicode(capfirst(opts.get_field(unique_for).verbose_name)),
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   826
            'lookup': lookup_type,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   827
        }
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   828
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   829
    def unique_error_message(self, model_class, unique_check):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   830
        opts = model_class._meta
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   831
        model_name = capfirst(opts.verbose_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   832
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   833
        # A unique field
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   834
        if len(unique_check) == 1:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   835
            field_name = unique_check[0]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   836
            field_label = capfirst(opts.get_field(field_name).verbose_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   837
            # Insert the error into the error dict, very sneaky
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   838
            return _(u"%(model_name)s with this %(field_label)s already exists.") %  {
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   839
                'model_name': unicode(model_name),
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   840
                'field_label': unicode(field_label)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   841
            }
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   842
        # unique_together
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   843
        else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   844
            field_labels = map(lambda f: capfirst(opts.get_field(f).verbose_name), unique_check)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   845
            field_labels = get_text_list(field_labels, _('and'))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   846
            return _(u"%(model_name)s with this %(field_label)s already exists.") %  {
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   847
                'model_name': unicode(model_name),
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   848
                'field_label': unicode(field_labels)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   849
            }
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   850
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   851
    def full_clean(self, exclude=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   852
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   853
        Calls clean_fields, clean, and validate_unique, on the model,
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   854
        and raises a ``ValidationError`` for any errors that occured.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   855
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   856
        errors = {}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   857
        if exclude is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   858
            exclude = []
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   859
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   860
        try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   861
            self.clean_fields(exclude=exclude)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   862
        except ValidationError, e:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   863
            errors = e.update_error_dict(errors)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   864
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   865
        # Form.clean() is run even if other validation fails, so do the
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   866
        # same with Model.clean() for consistency.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   867
        try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   868
            self.clean()
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   869
        except ValidationError, e:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   870
            errors = e.update_error_dict(errors)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   871
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   872
        # Run unique checks, but only for fields that passed validation.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   873
        for name in errors.keys():
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   874
            if name != NON_FIELD_ERRORS and name not in exclude:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   875
                exclude.append(name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   876
        try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   877
            self.validate_unique(exclude=exclude)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   878
        except ValidationError, e:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   879
            errors = e.update_error_dict(errors)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   880
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   881
        if errors:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   882
            raise ValidationError(errors)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   883
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   884
    def clean_fields(self, exclude=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   885
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   886
        Cleans all fields and raises a ValidationError containing message_dict
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   887
        of all validation errors if any occur.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   888
        """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   889
        if exclude is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   890
            exclude = []
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   891
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   892
        errors = {}
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   893
        for f in self._meta.fields:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   894
            if f.name in exclude:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   895
                continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   896
            # Skip validation for empty fields with blank=True. The developer
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   897
            # is responsible for making sure they have a valid value.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   898
            raw_value = getattr(self, f.attname)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   899
            if f.blank and raw_value in validators.EMPTY_VALUES:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   900
                continue
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   901
            try:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   902
                setattr(self, f.attname, f.clean(raw_value, self))
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   903
            except ValidationError, e:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   904
                errors[f.name] = e.messages
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   905
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   906
        if errors:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   907
            raise ValidationError(errors)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   908
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   909
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   910
############################################
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   911
# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   912
############################################
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   913
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   914
# ORDERING METHODS #########################
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   915
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   916
def method_set_order(ordered_obj, self, id_list, using=None):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   917
    if using is None:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   918
        using = DEFAULT_DB_ALIAS
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   919
    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   920
    order_name = ordered_obj._meta.order_with_respect_to.name
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   921
    # FIXME: It would be nice if there was an "update many" version of update
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   922
    # for situations like this.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   923
    for i, j in enumerate(id_list):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   924
        ordered_obj.objects.filter(**{'pk': j, order_name: rel_val}).update(_order=i)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   925
    transaction.commit_unless_managed(using=using)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   926
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   927
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   928
def method_get_order(ordered_obj, self):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   929
    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   930
    order_name = ordered_obj._meta.order_with_respect_to.name
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   931
    pk_name = ordered_obj._meta.pk.name
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   932
    return [r[pk_name] for r in
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   933
            ordered_obj.objects.filter(**{order_name: rel_val}).values(pk_name)]
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   934
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   935
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   936
##############################################
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   937
# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) #
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   938
##############################################
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   939
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   940
def get_absolute_url(opts, func, self, *args, **kwargs):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   941
    return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self, *args, **kwargs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   942
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   943
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   944
########
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   945
# MISC #
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   946
########
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   947
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   948
class Empty(object):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   949
    pass
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   950
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   951
def simple_class_factory(model, attrs):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   952
    """Used to unpickle Models without deferred fields.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   953
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   954
    We need to do this the hard way, rather than just using
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   955
    the default __reduce__ implementation, because of a
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   956
    __deepcopy__ problem in Python 2.4
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   957
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   958
    return model
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   959
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   960
def model_unpickle(model, attrs, factory):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   961
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   962
    Used to unpickle Model subclasses with deferred fields.
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   963
    """
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   964
    cls = factory(model, attrs)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   965
    return cls.__new__(cls)
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   966
model_unpickle.__safe_for_unpickle__ = True
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   967
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   968
if sys.version_info < (2, 5):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   969
    # Prior to Python 2.5, Exception was an old-style class
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   970
    def subclass_exception(name, parents, unused):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   971
        return types.ClassType(name, parents, {})
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   972
else:
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   973
    def subclass_exception(name, parents, module):
77b6da96e6f1 update django
ymh <ymh.work@gmail.com>
parents:
diff changeset
   974
        return type(name, parents, {'__module__': module})