~ubuntu-branches/ubuntu/jaunty/python-django/jaunty

« back to all changes in this revision

Viewing changes to django/db/models/base.py

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant, Eddy Mulyono
  • Date: 2008-09-16 12:18:47 UTC
  • mfrom: (1.1.5 upstream) (4.1.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080916121847-mg225rg5mnsdqzr0
Tags: 1.0-1ubuntu1
* Merge from Debian (LP: #264191), remaining changes:
  - Run test suite on build.

[Eddy Mulyono]
* Update patch to workaround network test case failures.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
import django.db.models.manipulators
2
 
import django.db.models.manager
3
 
from django.core import validators
4
 
from django.core.exceptions import ObjectDoesNotExist
5
 
from django.db.models.fields import AutoField, ImageField, FieldDoesNotExist
6
 
from django.db.models.fields.related import OneToOneRel, ManyToOneRel
7
 
from django.db.models.query import delete_objects
8
 
from django.db.models.options import Options, AdminOptions
9
 
from django.db import connection, backend, transaction
 
1
import copy
 
2
import types
 
3
import sys
 
4
import os
 
5
from itertools import izip
 
6
try:
 
7
    set
 
8
except NameError:
 
9
    from sets import Set as set     # Python 2.3 fallback.
 
10
 
 
11
import django.db.models.manager     # Imported to register signal handler.
 
12
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, FieldError
 
13
from django.db.models.fields import AutoField
 
14
from django.db.models.fields.related import OneToOneRel, ManyToOneRel, OneToOneField
 
15
from django.db.models.query import delete_objects, Q, CollectedObjects
 
16
from django.db.models.options import Options
 
17
from django.db import connection, transaction, DatabaseError
10
18
from django.db.models import signals
11
19
from django.db.models.loading import register_models, get_model
12
 
from django.dispatch import dispatcher
13
 
from django.utils.datastructures import SortedDict
14
20
from django.utils.functional import curry
 
21
from django.utils.encoding import smart_str, force_unicode, smart_unicode
15
22
from django.conf import settings
16
 
from itertools import izip
17
 
import types
18
 
import sys
19
 
import os
 
23
 
20
24
 
21
25
class ModelBase(type):
22
 
    "Metaclass for all models"
 
26
    """
 
27
    Metaclass for all models.
 
28
    """
23
29
    def __new__(cls, name, bases, attrs):
24
 
        # If this isn't a subclass of Model, don't do anything special.
25
 
        if name == 'Model' or not filter(lambda b: issubclass(b, Model), bases):
26
 
            return super(ModelBase, cls).__new__(cls, name, bases, attrs)
 
30
        super_new = super(ModelBase, cls).__new__
 
31
        parents = [b for b in bases if isinstance(b, ModelBase)]
 
32
        if not parents:
 
33
            # If this isn't a subclass of Model, don't do anything special.
 
34
            return super_new(cls, name, bases, attrs)
27
35
 
28
36
        # Create the class.
29
 
        new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')})
30
 
        new_class.add_to_class('_meta', Options(attrs.pop('Meta', None)))
31
 
        new_class.add_to_class('DoesNotExist', types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {}))
32
 
 
33
 
        # Build complete list of parents
34
 
        for base in bases:
35
 
            # TODO: Checking for the presence of '_meta' is hackish.
36
 
            if '_meta' in dir(base):
37
 
                new_class._meta.parents.append(base)
38
 
                new_class._meta.parents.extend(base._meta.parents)
39
 
 
40
 
        model_module = sys.modules[new_class.__module__]
41
 
 
42
 
        if getattr(new_class._meta, 'app_label', None) is None:
 
37
        module = attrs.pop('__module__')
 
38
        new_class = super_new(cls, name, bases, {'__module__': module})
 
39
        attr_meta = attrs.pop('Meta', None)
 
40
        abstract = getattr(attr_meta, 'abstract', False)
 
41
        if not attr_meta:
 
42
            meta = getattr(new_class, 'Meta', None)
 
43
        else:
 
44
            meta = attr_meta
 
45
        base_meta = getattr(new_class, '_meta', None)
 
46
 
 
47
        if getattr(meta, 'app_label', None) is None:
43
48
            # Figure out the app_label by looking one level up.
44
49
            # For 'django.contrib.sites.models', this would be 'sites'.
45
 
            new_class._meta.app_label = model_module.__name__.split('.')[-2]
 
50
            model_module = sys.modules[new_class.__module__]
 
51
            kwargs = {"app_label": model_module.__name__.split('.')[-2]}
 
52
        else:
 
53
            kwargs = {}
 
54
 
 
55
        new_class.add_to_class('_meta', Options(meta, **kwargs))
 
56
        if not abstract:
 
57
            new_class.add_to_class('DoesNotExist',
 
58
                    subclass_exception('DoesNotExist', ObjectDoesNotExist, module))
 
59
            new_class.add_to_class('MultipleObjectsReturned',
 
60
                    subclass_exception('MultipleObjectsReturned', MultipleObjectsReturned, module))
 
61
            if base_meta and not base_meta.abstract:
 
62
                # Non-abstract child classes inherit some attributes from their
 
63
                # non-abstract parent (unless an ABC comes before it in the
 
64
                # method resolution order).
 
65
                if not hasattr(meta, 'ordering'):
 
66
                    new_class._meta.ordering = base_meta.ordering
 
67
                if not hasattr(meta, 'get_latest_by'):
 
68
                    new_class._meta.get_latest_by = base_meta.get_latest_by
 
69
 
 
70
        if getattr(new_class, '_default_manager', None):
 
71
            new_class._default_manager = None
46
72
 
47
73
        # Bail out early if we have already created this class.
48
74
        m = get_model(new_class._meta.app_label, name, False)
53
79
        for obj_name, obj in attrs.items():
54
80
            new_class.add_to_class(obj_name, obj)
55
81
 
56
 
        # Add Fields inherited from parents
57
 
        for parent in new_class._meta.parents:
58
 
            for field in parent._meta.fields:
59
 
                # Only add parent fields if they aren't defined for this class.
60
 
                try:
61
 
                    new_class._meta.get_field(field.name)
62
 
                except FieldDoesNotExist:
63
 
                    field.contribute_to_class(new_class, field.name)
 
82
        # Do the appropriate setup for any model parents.
 
83
        o2o_map = dict([(f.rel.to, f) for f in new_class._meta.local_fields
 
84
                if isinstance(f, OneToOneField)])
 
85
        for base in parents:
 
86
            if not hasattr(base, '_meta'):
 
87
                # Things without _meta aren't functional models, so they're
 
88
                # uninteresting parents.
 
89
                continue
 
90
 
 
91
            # All the fields of any type declared on this model
 
92
            new_fields = new_class._meta.local_fields + \
 
93
                         new_class._meta.local_many_to_many + \
 
94
                         new_class._meta.virtual_fields
 
95
            field_names = set([f.name for f in new_fields])
 
96
 
 
97
            if not base._meta.abstract:
 
98
                # Concrete classes...
 
99
                if base in o2o_map:
 
100
                    field = o2o_map[base]
 
101
                    field.primary_key = True
 
102
                    new_class._meta.setup_pk(field)
 
103
                else:
 
104
                    attr_name = '%s_ptr' % base._meta.module_name
 
105
                    field = OneToOneField(base, name=attr_name,
 
106
                            auto_created=True, parent_link=True)
 
107
                    new_class.add_to_class(attr_name, field)
 
108
                new_class._meta.parents[base] = field
 
109
 
 
110
            else:
 
111
                # .. and abstract ones.
 
112
 
 
113
                # Check for clashes between locally declared fields and those
 
114
                # on the ABC.
 
115
                parent_fields = base._meta.local_fields + base._meta.local_many_to_many
 
116
                for field in parent_fields:
 
117
                    if field.name in field_names:
 
118
                        raise FieldError('Local field %r in class %r clashes '\
 
119
                                         'with field of similar name from '\
 
120
                                         'abstract base class %r' % \
 
121
                                            (field.name, name, base.__name__))
 
122
                    new_class.add_to_class(field.name, copy.deepcopy(field))
 
123
 
 
124
                # Pass any non-abstract parent classes onto child.
 
125
                new_class._meta.parents.update(base._meta.parents)
 
126
 
 
127
            # Inherit managers from the abstract base classes.
 
128
            base_managers = base._meta.abstract_managers
 
129
            base_managers.sort()
 
130
            for _, mgr_name, manager in base_managers:
 
131
                val = getattr(new_class, mgr_name, None)
 
132
                if not val or val is manager:
 
133
                    new_manager = manager._copy_to_model(new_class)
 
134
                    new_class.add_to_class(mgr_name, new_manager)
 
135
 
 
136
            # Inherit virtual fields (like GenericForeignKey) from the parent class
 
137
            for field in base._meta.virtual_fields:
 
138
                if base._meta.abstract and field.name in field_names:
 
139
                    raise FieldError('Local field %r in class %r clashes '\
 
140
                                     'with field of similar name from '\
 
141
                                     'abstract base class %r' % \
 
142
                                        (field.name, name, base.__name__))
 
143
                new_class.add_to_class(field.name, copy.deepcopy(field))
 
144
 
 
145
        if abstract:
 
146
            # Abstract base models can't be instantiated and don't appear in
 
147
            # the list of models for an app. We do the final setup for them a
 
148
            # little differently from normal models.
 
149
            attr_meta.abstract = False
 
150
            new_class.Meta = attr_meta
 
151
            return new_class
64
152
 
65
153
        new_class._prepare()
66
 
 
67
154
        register_models(new_class._meta.app_label, new_class)
 
155
 
68
156
        # Because of the way imports happen (recursively), we may or may not be
69
 
        # the first class for this model to register with the framework. There
70
 
        # should only be one class for each model, so we must always return the
 
157
        # the first time this model tries to register with the framework. There
 
158
        # should only be one class for each model, so we always return the
71
159
        # registered version.
72
160
        return get_model(new_class._meta.app_label, name, False)
73
161
 
 
162
    def add_to_class(cls, name, value):
 
163
        if hasattr(value, 'contribute_to_class'):
 
164
            value.contribute_to_class(cls, name)
 
165
        else:
 
166
            setattr(cls, name, value)
 
167
 
 
168
    def _prepare(cls):
 
169
        """
 
170
        Creates some methods once self._meta has been populated.
 
171
        """
 
172
        opts = cls._meta
 
173
        opts._prepare(cls)
 
174
 
 
175
        if opts.order_with_respect_to:
 
176
            cls.get_next_in_order = curry(cls._get_next_or_previous_in_order, is_next=True)
 
177
            cls.get_previous_in_order = curry(cls._get_next_or_previous_in_order, is_next=False)
 
178
            setattr(opts.order_with_respect_to.rel.to, 'get_%s_order' % cls.__name__.lower(), curry(method_get_order, cls))
 
179
            setattr(opts.order_with_respect_to.rel.to, 'set_%s_order' % cls.__name__.lower(), curry(method_set_order, cls))
 
180
 
 
181
        # Give the class a docstring -- its definition.
 
182
        if cls.__doc__ is None:
 
183
            cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join([f.attname for f in opts.fields]))
 
184
 
 
185
        if hasattr(cls, 'get_absolute_url'):
 
186
            cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url)
 
187
 
 
188
        signals.class_prepared.send(sender=cls)
 
189
 
 
190
 
74
191
class Model(object):
75
192
    __metaclass__ = ModelBase
76
193
 
77
 
    def _get_pk_val(self):
78
 
        return getattr(self, self._meta.pk.attname)
79
 
 
80
 
    def __repr__(self):
81
 
        return '<%s: %s>' % (self.__class__.__name__, self)
82
 
 
83
 
    def __str__(self):
84
 
        return '%s object' % self.__class__.__name__
85
 
 
86
 
    def __eq__(self, other):
87
 
        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
88
 
 
89
 
    def __ne__(self, other):
90
 
        return not self.__eq__(other)
91
 
 
92
194
    def __init__(self, *args, **kwargs):
93
 
        dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
94
 
        
 
195
        signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
 
196
 
95
197
        # There is a rather weird disparity here; if kwargs, it's set, then args
96
 
        # overrides it. It should be one or the other; don't duplicate the work 
 
198
        # overrides it. It should be one or the other; don't duplicate the work
97
199
        # The reason for the kwargs check is that standard iterator passes in by
98
 
        # args, and nstantiation for iteration is 33% faster.
 
200
        # args, and instantiation for iteration is 33% faster.
99
201
        args_len = len(args)
100
202
        if args_len > len(self._meta.fields):
101
203
            # Daft, but matches old exception sans the err msg.
117
219
                # Maintain compatibility with existing calls.
118
220
                if isinstance(field.rel, ManyToOneRel):
119
221
                    kwargs.pop(field.attname, None)
120
 
        
 
222
 
121
223
        # Now we're left with the unprocessed fields that *must* come from
122
224
        # keywords, or default.
123
 
        
 
225
 
124
226
        for field in fields_iter:
 
227
            rel_obj = None
125
228
            if kwargs:
126
229
                if isinstance(field.rel, ManyToOneRel):
127
230
                    try:
138
241
                        # pass in "None" for related objects if it's allowed.
139
242
                        if rel_obj is None and field.null:
140
243
                            val = None
141
 
                        else:
142
 
                            try:
143
 
                                val = getattr(rel_obj, field.rel.get_related_field().attname)
144
 
                            except AttributeError:
145
 
                                raise TypeError("Invalid value: %r should be a %s instance, not a %s" % 
146
 
                                    (field.name, field.rel.to, type(rel_obj)))
147
244
                else:
148
245
                    val = kwargs.pop(field.attname, field.get_default())
149
246
            else:
150
247
                val = field.get_default()
151
 
            setattr(self, field.attname, val)
 
248
            # If we got passed a related instance, set it using the field.name
 
249
            # instead of field.attname (e.g. "user" instead of "user_id") so
 
250
            # that the object gets properly cached (and type checked) by the
 
251
            # RelatedObjectDescriptor.
 
252
            if rel_obj:
 
253
                setattr(self, field.name, rel_obj)
 
254
            else:
 
255
                setattr(self, field.attname, val)
152
256
 
153
257
        if kwargs:
154
258
            for prop in kwargs.keys():
159
263
                    pass
160
264
            if kwargs:
161
265
                raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0]
162
 
        dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self)
163
 
 
164
 
    def add_to_class(cls, name, value):
165
 
        if name == 'Admin':
166
 
            assert type(value) == types.ClassType, "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value))
167
 
            value = AdminOptions(**dict([(k, v) for k, v in value.__dict__.items() if not k.startswith('_')]))
168
 
        if hasattr(value, 'contribute_to_class'):
169
 
            value.contribute_to_class(cls, name)
 
266
        signals.post_init.send(sender=self.__class__, instance=self)
 
267
 
 
268
    def __repr__(self):
 
269
        return smart_str(u'<%s: %s>' % (self.__class__.__name__, unicode(self)))
 
270
 
 
271
    def __str__(self):
 
272
        if hasattr(self, '__unicode__'):
 
273
            return force_unicode(self).encode('utf-8')
 
274
        return '%s object' % self.__class__.__name__
 
275
 
 
276
    def __eq__(self, other):
 
277
        return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
 
278
 
 
279
    def __ne__(self, other):
 
280
        return not self.__eq__(other)
 
281
 
 
282
    def __hash__(self):
 
283
        return hash(self._get_pk_val())
 
284
 
 
285
    def _get_pk_val(self, meta=None):
 
286
        if not meta:
 
287
            meta = self._meta
 
288
        return getattr(self, meta.pk.attname)
 
289
 
 
290
    def _set_pk_val(self, value):
 
291
        return setattr(self, self._meta.pk.attname, value)
 
292
 
 
293
    pk = property(_get_pk_val, _set_pk_val)
 
294
 
 
295
    def save(self, force_insert=False, force_update=False):
 
296
        """
 
297
        Saves the current instance. Override this in a subclass if you want to
 
298
        control the saving process.
 
299
 
 
300
        The 'force_insert' and 'force_update' parameters can be used to insist
 
301
        that the "save" must be an SQL insert or update (or equivalent for
 
302
        non-SQL backends), respectively. Normally, they should not be set.
 
303
        """
 
304
        if force_insert and force_update:
 
305
            raise ValueError("Cannot force both insert and updating in "
 
306
                    "model saving.")
 
307
        self.save_base(force_insert=force_insert, force_update=force_update)
 
308
 
 
309
    save.alters_data = True
 
310
 
 
311
    def save_base(self, raw=False, cls=None, force_insert=False,
 
312
            force_update=False):
 
313
        """
 
314
        Does the heavy-lifting involved in saving. Subclasses shouldn't need to
 
315
        override this method. It's separate from save() in order to hide the
 
316
        need for overrides of save() to pass around internal-only parameters
 
317
        ('raw' and 'cls').
 
318
        """
 
319
        assert not (force_insert and force_update)
 
320
        if not cls:
 
321
            cls = self.__class__
 
322
            meta = self._meta
 
323
            signal = True
 
324
            signals.pre_save.send(sender=self.__class__, instance=self, raw=raw)
170
325
        else:
171
 
            setattr(cls, name, value)
172
 
    add_to_class = classmethod(add_to_class)
173
 
 
174
 
    def _prepare(cls):
175
 
        # Creates some methods once self._meta has been populated.
176
 
        opts = cls._meta
177
 
        opts._prepare(cls)
178
 
 
179
 
        if opts.order_with_respect_to:
180
 
            cls.get_next_in_order = curry(cls._get_next_or_previous_in_order, is_next=True)
181
 
            cls.get_previous_in_order = curry(cls._get_next_or_previous_in_order, is_next=False)
182
 
            setattr(opts.order_with_respect_to.rel.to, 'get_%s_order' % cls.__name__.lower(), curry(method_get_order, cls))
183
 
            setattr(opts.order_with_respect_to.rel.to, 'set_%s_order' % cls.__name__.lower(), curry(method_set_order, cls))
184
 
 
185
 
        # Give the class a docstring -- its definition.
186
 
        if cls.__doc__ is None:
187
 
            cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join([f.attname for f in opts.fields]))
188
 
 
189
 
        if hasattr(cls, 'get_absolute_url'):
190
 
            cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url)
191
 
 
192
 
        dispatcher.send(signal=signals.class_prepared, sender=cls)
193
 
 
194
 
    _prepare = classmethod(_prepare)
195
 
 
196
 
    def save(self):
197
 
        dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self)
198
 
 
199
 
        non_pks = [f for f in self._meta.fields if not f.primary_key]
200
 
        cursor = connection.cursor()
 
326
            meta = cls._meta
 
327
            signal = False
 
328
 
 
329
        # If we are in a raw save, save the object exactly as presented.
 
330
        # That means that we don't try to be smart about saving attributes
 
331
        # that might have come from the parent class - we just save the
 
332
        # attributes we have been given to the class we have been given.
 
333
        if not raw:
 
334
            for parent, field in meta.parents.items():
 
335
                # At this point, parent's primary key field may be unknown
 
336
                # (for example, from administration form which doesn't fill
 
337
                # this field). If so, fill it.
 
338
                if getattr(self, parent._meta.pk.attname) is None and getattr(self, field.attname) is not None:
 
339
                    setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
 
340
 
 
341
                self.save_base(raw, parent)
 
342
                setattr(self, field.attname, self._get_pk_val(parent._meta))
 
343
 
 
344
        non_pks = [f for f in meta.local_fields if not f.primary_key]
201
345
 
202
346
        # First, try an UPDATE. If that doesn't update anything, do an INSERT.
203
 
        pk_val = self._get_pk_val()
204
 
        pk_set = bool(pk_val)
 
347
        pk_val = self._get_pk_val(meta)
 
348
        pk_set = pk_val is not None
205
349
        record_exists = True
 
350
        manager = cls._default_manager
206
351
        if pk_set:
207
352
            # Determine whether a record with the primary key already exists.
208
 
            cursor.execute("SELECT 1 FROM %s WHERE %s=%%s LIMIT 1" % \
209
 
                (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)), [pk_val])
210
 
            # If it does already exist, do an UPDATE.
211
 
            if cursor.fetchone():
212
 
                db_values = [f.get_db_prep_save(f.pre_save(self, False)) for f in non_pks]
213
 
                if db_values:
214
 
                    cursor.execute("UPDATE %s SET %s WHERE %s=%%s" % \
215
 
                        (backend.quote_name(self._meta.db_table),
216
 
                        ','.join(['%s=%%s' % backend.quote_name(f.column) for f in non_pks]),
217
 
                        backend.quote_name(self._meta.pk.column)),
218
 
                        db_values + [pk_val])
 
353
            if (force_update or (not force_insert and
 
354
                    manager.filter(pk=pk_val).extra(select={'a': 1}).values('a').order_by())):
 
355
                # It does already exist, so do an UPDATE.
 
356
                if force_update or non_pks:
 
357
                    values = [(f, None, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, False))) for f in non_pks]
 
358
                    rows = manager.filter(pk=pk_val)._update(values)
 
359
                    if force_update and not rows:
 
360
                        raise DatabaseError("Forced update did not affect any rows.")
219
361
            else:
220
362
                record_exists = False
221
363
        if not pk_set or not record_exists:
222
 
            field_names = [backend.quote_name(f.column) for f in self._meta.fields if not isinstance(f, AutoField)]
223
 
            db_values = [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if not isinstance(f, AutoField)]
224
 
            # If the PK has been manually set, respect that.
225
 
            if pk_set:
226
 
                field_names += [f.column for f in self._meta.fields if isinstance(f, AutoField)]
227
 
                db_values += [f.get_db_prep_save(f.pre_save(self, True)) for f in self._meta.fields if isinstance(f, AutoField)]
228
 
            placeholders = ['%s'] * len(field_names)
229
 
            if self._meta.order_with_respect_to:
230
 
                field_names.append(backend.quote_name('_order'))
231
 
                # TODO: This assumes the database supports subqueries.
232
 
                placeholders.append('(SELECT COUNT(*) FROM %s WHERE %s = %%s)' % \
233
 
                    (backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.order_with_respect_to.column)))
234
 
                db_values.append(getattr(self, self._meta.order_with_respect_to.attname))
235
 
            if db_values:
236
 
                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" % \
237
 
                    (backend.quote_name(self._meta.db_table), ','.join(field_names),
238
 
                    ','.join(placeholders)), db_values)
 
364
            if not pk_set:
 
365
                if force_update:
 
366
                    raise ValueError("Cannot force an update in save() with no primary key.")
 
367
                values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields if not isinstance(f, AutoField)]
 
368
            else:
 
369
                values = [(f, f.get_db_prep_save(raw and getattr(self, f.attname) or f.pre_save(self, True))) for f in meta.local_fields]
 
370
 
 
371
            if meta.order_with_respect_to:
 
372
                field = meta.order_with_respect_to
 
373
                values.append((meta.get_field_by_name('_order')[0], manager.filter(**{field.name: getattr(self, field.attname)}).count()))
 
374
            record_exists = False
 
375
 
 
376
            update_pk = bool(meta.has_auto_field and not pk_set)
 
377
            if values:
 
378
                # Create a new record.
 
379
                result = manager._insert(values, return_id=update_pk)
239
380
            else:
240
381
                # Create a new record with defaults for everything.
241
 
                cursor.execute("INSERT INTO %s (%s) VALUES (%s)" %
242
 
                    (backend.quote_name(self._meta.db_table),
243
 
                     backend.quote_name(self._meta.pk.column),
244
 
                     backend.get_pk_default_value()))
245
 
            if self._meta.has_auto_field and not pk_set:
246
 
                setattr(self, self._meta.pk.attname, backend.get_last_insert_id(cursor, self._meta.db_table, self._meta.pk.column))
 
382
                result = manager._insert([(meta.pk, connection.ops.pk_default_value())], return_id=update_pk, raw_values=True)
 
383
 
 
384
            if update_pk:
 
385
                setattr(self, meta.pk.attname, result)
247
386
        transaction.commit_unless_managed()
248
387
 
249
 
        # Run any post-save hooks.
250
 
        dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self)
251
 
 
252
 
    save.alters_data = True
253
 
 
254
 
    def validate(self):
255
 
        """
256
 
        First coerces all fields on this instance to their proper Python types.
257
 
        Then runs validation on every field. Returns a dictionary of
258
 
        field_name -> error_list.
259
 
        """
260
 
        error_dict = {}
261
 
        invalid_python = {}
262
 
        for f in self._meta.fields:
263
 
            try:
264
 
                setattr(self, f.attname, f.to_python(getattr(self, f.attname, f.get_default())))
265
 
            except validators.ValidationError, e:
266
 
                error_dict[f.name] = e.messages
267
 
                invalid_python[f.name] = 1
268
 
        for f in self._meta.fields:
269
 
            if f.name in invalid_python:
270
 
                continue
271
 
            errors = f.validate_full(getattr(self, f.attname, f.get_default()), self.__dict__)
272
 
            if errors:
273
 
                error_dict[f.name] = errors
274
 
        return error_dict
275
 
 
276
 
    def _collect_sub_objects(self, seen_objs):
277
 
        """
278
 
        Recursively populates seen_objs with all objects related to this object.
279
 
        When done, seen_objs will be in the format:
280
 
            {model_class: {pk_val: obj, pk_val: obj, ...},
281
 
             model_class: {pk_val: obj, pk_val: obj, ...}, ...}
 
388
        if signal:
 
389
            signals.post_save.send(sender=self.__class__, instance=self,
 
390
                created=(not record_exists), raw=raw)
 
391
 
 
392
    save_base.alters_data = True
 
393
 
 
394
    def _collect_sub_objects(self, seen_objs, parent=None, nullable=False):
 
395
        """
 
396
        Recursively populates seen_objs with all objects related to this
 
397
        object.
 
398
 
 
399
        When done, seen_objs.items() will be in the format:
 
400
            [(model_class, {pk_val: obj, pk_val: obj, ...}),
 
401
             (model_class, {pk_val: obj, pk_val: obj, ...}), ...]
282
402
        """
283
403
        pk_val = self._get_pk_val()
284
 
        if pk_val in seen_objs.setdefault(self.__class__, {}):
 
404
        if seen_objs.add(self.__class__, pk_val, self, parent, nullable):
285
405
            return
286
 
        seen_objs.setdefault(self.__class__, {})[pk_val] = self
287
406
 
288
407
        for related in self._meta.get_all_related_objects():
289
408
            rel_opts_name = related.get_accessor_name()
293
412
                except ObjectDoesNotExist:
294
413
                    pass
295
414
                else:
296
 
                    sub_obj._collect_sub_objects(seen_objs)
 
415
                    sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null)
297
416
            else:
298
417
                for sub_obj in getattr(self, rel_opts_name).all():
299
 
                    sub_obj._collect_sub_objects(seen_objs)
 
418
                    sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null)
 
419
 
 
420
        # Handle any ancestors (for the model-inheritance case). We do this by
 
421
        # traversing to the most remote parent classes -- those with no parents
 
422
        # themselves -- and then adding those instances to the collection. That
 
423
        # will include all the child instances down to "self".
 
424
        parent_stack = self._meta.parents.values()
 
425
        while parent_stack:
 
426
            link = parent_stack.pop()
 
427
            parent_obj = getattr(self, link.name)
 
428
            if parent_obj._meta.parents:
 
429
                parent_stack.extend(parent_obj._meta.parents.values())
 
430
                continue
 
431
            # At this point, parent_obj is base class (no ancestor models). So
 
432
            # delete it and all its descendents.
 
433
            parent_obj._collect_sub_objects(seen_objs)
300
434
 
301
435
    def delete(self):
302
436
        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)
303
437
 
304
 
        # Find all the objects than need to be deleted
305
 
        seen_objs = SortedDict()
 
438
        # Find all the objects than need to be deleted.
 
439
        seen_objs = CollectedObjects()
306
440
        self._collect_sub_objects(seen_objs)
307
441
 
308
 
        # Actually delete the objects
 
442
        # Actually delete the objects.
309
443
        delete_objects(seen_objs)
310
444
 
311
445
    delete.alters_data = True
312
446
 
313
447
    def _get_FIELD_display(self, field):
314
448
        value = getattr(self, field.attname)
315
 
        return dict(field.choices).get(value, value)
 
449
        return force_unicode(dict(field.flatchoices).get(value, value), strings_only=True)
316
450
 
317
451
    def _get_next_or_previous_by_FIELD(self, field, is_next, **kwargs):
318
 
        op = is_next and '>' or '<'
319
 
        where = '(%s %s %%s OR (%s = %%s AND %s.%s %s %%s))' % \
320
 
            (backend.quote_name(field.column), op, backend.quote_name(field.column),
321
 
            backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column), op)
322
 
        param = str(getattr(self, field.attname))
323
 
        q = self.__class__._default_manager.filter(**kwargs).order_by((not is_next and '-' or '') + field.name, (not is_next and '-' or '') + self._meta.pk.name)
324
 
        q._where.append(where)
325
 
        q._params.extend([param, param, getattr(self, self._meta.pk.attname)])
 
452
        op = is_next and 'gt' or 'lt'
 
453
        order = not is_next and '-' or ''
 
454
        param = smart_str(getattr(self, field.attname))
 
455
        q = Q(**{'%s__%s' % (field.name, op): param})
 
456
        q = q|Q(**{field.name: param, 'pk__%s' % op: self.pk})
 
457
        qs = self.__class__._default_manager.filter(**kwargs).filter(q).order_by('%s%s' % (order, field.name), '%spk' % order)
326
458
        try:
327
 
            return q[0]
 
459
            return qs[0]
328
460
        except IndexError:
329
461
            raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name
330
462
 
331
463
    def _get_next_or_previous_in_order(self, is_next):
332
464
        cachename = "__%s_order_cache" % is_next
333
465
        if not hasattr(self, cachename):
 
466
            qn = connection.ops.quote_name
334
467
            op = is_next and '>' or '<'
 
468
            order = not is_next and '-_order' or '_order'
335
469
            order_field = self._meta.order_with_respect_to
 
470
            # FIXME: When querysets support nested queries, this can be turned
 
471
            # into a pure queryset operation.
336
472
            where = ['%s %s (SELECT %s FROM %s WHERE %s=%%s)' % \
337
 
                (backend.quote_name('_order'), op, backend.quote_name('_order'),
338
 
                backend.quote_name(self._meta.db_table), backend.quote_name(self._meta.pk.column)),
339
 
                '%s=%%s' % backend.quote_name(order_field.column)]
340
 
            params = [self._get_pk_val(), getattr(self, order_field.attname)]
341
 
            obj = self._default_manager.order_by('_order').extra(where=where, params=params)[:1].get()
 
473
                (qn('_order'), op, qn('_order'),
 
474
                qn(self._meta.db_table), qn(self._meta.pk.column))]
 
475
            params = [self.pk]
 
476
            obj = self._default_manager.filter(**{order_field.name: getattr(self, order_field.attname)}).extra(where=where, params=params).order_by(order)[:1].get()
342
477
            setattr(self, cachename, obj)
343
478
        return getattr(self, cachename)
344
479
 
345
 
    def _get_FIELD_filename(self, field):
346
 
        if getattr(self, field.attname): # value is not blank
347
 
            return os.path.join(settings.MEDIA_ROOT, getattr(self, field.attname))
348
 
        return ''
349
 
 
350
 
    def _get_FIELD_url(self, field):
351
 
        if getattr(self, field.attname): # value is not blank
352
 
            import urlparse
353
 
            return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/')
354
 
        return ''
355
 
 
356
 
    def _get_FIELD_size(self, field):
357
 
        return os.path.getsize(self._get_FIELD_filename(field))
358
 
 
359
 
    def _save_FIELD_file(self, field, filename, raw_contents, save=True):
360
 
        directory = field.get_directory_name()
361
 
        try: # Create the date-based directory if it doesn't exist.
362
 
            os.makedirs(os.path.join(settings.MEDIA_ROOT, directory))
363
 
        except OSError: # Directory probably already exists.
364
 
            pass
365
 
        filename = field.get_filename(filename)
366
 
 
367
 
        # If the filename already exists, keep adding an underscore to the name of
368
 
        # the file until the filename doesn't exist.
369
 
        while os.path.exists(os.path.join(settings.MEDIA_ROOT, filename)):
370
 
            try:
371
 
                dot_index = filename.rindex('.')
372
 
            except ValueError: # filename has no dot
373
 
                filename += '_'
374
 
            else:
375
 
                filename = filename[:dot_index] + '_' + filename[dot_index:]
376
 
 
377
 
        # Write the file to disk.
378
 
        setattr(self, field.attname, filename)
379
 
 
380
 
        full_filename = self._get_FIELD_filename(field)
381
 
        fp = open(full_filename, 'wb')
382
 
        fp.write(raw_contents)
383
 
        fp.close()
384
 
 
385
 
        # Save the width and/or height, if applicable.
386
 
        if isinstance(field, ImageField) and (field.width_field or field.height_field):
387
 
            from django.utils.images import get_image_dimensions
388
 
            width, height = get_image_dimensions(full_filename)
389
 
            if field.width_field:
390
 
                setattr(self, field.width_field, width)
391
 
            if field.height_field:
392
 
                setattr(self, field.height_field, height)
393
 
 
394
 
        # Save the object because it has changed unless save is False
395
 
        if save:
396
 
            self.save()
397
 
 
398
 
    _save_FIELD_file.alters_data = True
399
 
 
400
 
    def _get_FIELD_width(self, field):
401
 
        return self._get_image_dimensions(field)[0]
402
 
 
403
 
    def _get_FIELD_height(self, field):
404
 
        return self._get_image_dimensions(field)[1]
405
 
 
406
 
    def _get_image_dimensions(self, field):
407
 
        cachename = "__%s_dimensions_cache" % field.name
408
 
        if not hasattr(self, cachename):
409
 
            from django.utils.images import get_image_dimensions
410
 
            filename = self._get_FIELD_filename(field)
411
 
            setattr(self, cachename, get_image_dimensions(filename))
412
 
        return getattr(self, cachename)
 
480
 
413
481
 
414
482
############################################
415
483
# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
418
486
# ORDERING METHODS #########################
419
487
 
420
488
def method_set_order(ordered_obj, self, id_list):
421
 
    cursor = connection.cursor()
422
 
    # Example: "UPDATE poll_choices SET _order = %s WHERE poll_id = %s AND id = %s"
423
 
    sql = "UPDATE %s SET %s = %%s WHERE %s = %%s AND %s = %%s" % \
424
 
        (backend.quote_name(ordered_obj._meta.db_table), backend.quote_name('_order'),
425
 
        backend.quote_name(ordered_obj._meta.order_with_respect_to.column),
426
 
        backend.quote_name(ordered_obj._meta.pk.column))
427
489
    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
428
 
    cursor.executemany(sql, [(i, rel_val, j) for i, j in enumerate(id_list)])
 
490
    order_name = ordered_obj._meta.order_with_respect_to.name
 
491
    # FIXME: It would be nice if there was an "update many" version of update
 
492
    # for situations like this.
 
493
    for i, j in enumerate(id_list):
 
494
        ordered_obj.objects.filter(**{'pk': j, order_name: rel_val}).update(_order=i)
429
495
    transaction.commit_unless_managed()
430
496
 
 
497
 
431
498
def method_get_order(ordered_obj, self):
432
 
    cursor = connection.cursor()
433
 
    # Example: "SELECT id FROM poll_choices WHERE poll_id = %s ORDER BY _order"
434
 
    sql = "SELECT %s FROM %s WHERE %s = %%s ORDER BY %s" % \
435
 
        (backend.quote_name(ordered_obj._meta.pk.column),
436
 
        backend.quote_name(ordered_obj._meta.db_table),
437
 
        backend.quote_name(ordered_obj._meta.order_with_respect_to.column),
438
 
        backend.quote_name('_order'))
439
499
    rel_val = getattr(self, ordered_obj._meta.order_with_respect_to.rel.field_name)
440
 
    cursor.execute(sql, [rel_val])
441
 
    return [r[0] for r in cursor.fetchall()]
 
500
    order_name = ordered_obj._meta.order_with_respect_to.name
 
501
    pk_name = ordered_obj._meta.pk.name
 
502
    return [r[pk_name] for r in
 
503
            ordered_obj.objects.filter(**{order_name: rel_val}).values(pk_name)]
 
504
 
442
505
 
443
506
##############################################
444
507
# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) #
445
508
##############################################
446
509
 
447
 
def get_absolute_url(opts, func, self):
448
 
    return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self)
 
510
def get_absolute_url(opts, func, self, *args, **kwargs):
 
511
    return settings.ABSOLUTE_URL_OVERRIDES.get('%s.%s' % (opts.app_label, opts.module_name), func)(self, *args, **kwargs)
 
512
 
 
513
 
 
514
########
 
515
# MISC #
 
516
########
 
517
 
 
518
class Empty(object):
 
519
    pass
 
520
 
 
521
if sys.version_info < (2, 5):
 
522
    # Prior to Python 2.5, Exception was an old-style class
 
523
    def subclass_exception(name, parent, unused):
 
524
        return types.ClassType(name, (parent,), {})
 
525
else:
 
526
    def subclass_exception(name, parent, module):
 
527
        return type(name, (parent,), {'__module__': module})