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
5
from itertools import izip
9
from sets import Set as set # Python 2.3 fallback.
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
21
25
class ModelBase(type):
22
"Metaclass for all models"
27
Metaclass for all models.
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)]
33
# If this isn't a subclass of Model, don't do anything special.
34
return super_new(cls, name, bases, attrs)
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,), {}))
33
# Build complete list of parents
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)
40
model_module = sys.modules[new_class.__module__]
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)
42
meta = getattr(new_class, 'Meta', None)
45
base_meta = getattr(new_class, '_meta', None)
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]}
55
new_class.add_to_class('_meta', Options(meta, **kwargs))
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
70
if getattr(new_class, '_default_manager', None):
71
new_class._default_manager = None
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)
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.
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)])
86
if not hasattr(base, '_meta'):
87
# Things without _meta aren't functional models, so they're
88
# uninteresting parents.
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])
97
if not base._meta.abstract:
100
field = o2o_map[base]
101
field.primary_key = True
102
new_class._meta.setup_pk(field)
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
111
# .. and abstract ones.
113
# Check for clashes between locally declared fields and those
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))
124
# Pass any non-abstract parent classes onto child.
125
new_class._meta.parents.update(base._meta.parents)
127
# Inherit managers from the abstract base classes.
128
base_managers = base._meta.abstract_managers
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)
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))
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
65
153
new_class._prepare()
67
154
register_models(new_class._meta.app_label, new_class)
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)
162
def add_to_class(cls, name, value):
163
if hasattr(value, 'contribute_to_class'):
164
value.contribute_to_class(cls, name)
166
setattr(cls, name, value)
170
Creates some methods once self._meta has been populated.
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))
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]))
185
if hasattr(cls, 'get_absolute_url'):
186
cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url)
188
signals.class_prepared.send(sender=cls)
74
191
class Model(object):
75
192
__metaclass__ = ModelBase
77
def _get_pk_val(self):
78
return getattr(self, self._meta.pk.attname)
81
return '<%s: %s>' % (self.__class__.__name__, self)
84
return '%s object' % self.__class__.__name__
86
def __eq__(self, other):
87
return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
89
def __ne__(self, other):
90
return not self.__eq__(other)
92
194
def __init__(self, *args, **kwargs):
93
dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs)
195
signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs)
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.
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)
164
def add_to_class(cls, name, value):
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)
269
return smart_str(u'<%s: %s>' % (self.__class__.__name__, unicode(self)))
272
if hasattr(self, '__unicode__'):
273
return force_unicode(self).encode('utf-8')
274
return '%s object' % self.__class__.__name__
276
def __eq__(self, other):
277
return isinstance(other, self.__class__) and self._get_pk_val() == other._get_pk_val()
279
def __ne__(self, other):
280
return not self.__eq__(other)
283
return hash(self._get_pk_val())
285
def _get_pk_val(self, meta=None):
288
return getattr(self, meta.pk.attname)
290
def _set_pk_val(self, value):
291
return setattr(self, self._meta.pk.attname, value)
293
pk = property(_get_pk_val, _set_pk_val)
295
def save(self, force_insert=False, force_update=False):
297
Saves the current instance. Override this in a subclass if you want to
298
control the saving process.
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.
304
if force_insert and force_update:
305
raise ValueError("Cannot force both insert and updating in "
307
self.save_base(force_insert=force_insert, force_update=force_update)
309
save.alters_data = True
311
def save_base(self, raw=False, cls=None, force_insert=False,
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
319
assert not (force_insert and force_update)
324
signals.pre_save.send(sender=self.__class__, instance=self, raw=raw)
171
setattr(cls, name, value)
172
add_to_class = classmethod(add_to_class)
175
# Creates some methods once self._meta has been populated.
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))
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]))
189
if hasattr(cls, 'get_absolute_url'):
190
cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url)
192
dispatcher.send(signal=signals.class_prepared, sender=cls)
194
_prepare = classmethod(_prepare)
197
dispatcher.send(signal=signals.pre_save, sender=self.__class__, instance=self)
199
non_pks = [f for f in self._meta.fields if not f.primary_key]
200
cursor = connection.cursor()
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.
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))
341
self.save_base(raw, parent)
342
setattr(self, field.attname, self._get_pk_val(parent._meta))
344
non_pks = [f for f in meta.local_fields if not f.primary_key]
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
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]
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.")
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.
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))
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)
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)]
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]
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
376
update_pk = bool(meta.has_auto_field and not pk_set)
378
# Create a new record.
379
result = manager._insert(values, return_id=update_pk)
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)
385
setattr(self, meta.pk.attname, result)
247
386
transaction.commit_unless_managed()
249
# Run any post-save hooks.
250
dispatcher.send(signal=signals.post_save, sender=self.__class__, instance=self)
252
save.alters_data = True
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.
262
for f in self._meta.fields:
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:
271
errors = f.validate_full(getattr(self, f.attname, f.get_default()), self.__dict__)
273
error_dict[f.name] = errors
276
def _collect_sub_objects(self, seen_objs):
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, ...}, ...}
389
signals.post_save.send(sender=self.__class__, instance=self,
390
created=(not record_exists), raw=raw)
392
save_base.alters_data = True
394
def _collect_sub_objects(self, seen_objs, parent=None, nullable=False):
396
Recursively populates seen_objs with all objects related to this
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, ...}), ...]
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):
286
seen_objs.setdefault(self.__class__, {})[pk_val] = self
288
407
for related in self._meta.get_all_related_objects():
289
408
rel_opts_name = related.get_accessor_name()
293
412
except ObjectDoesNotExist:
296
sub_obj._collect_sub_objects(seen_objs)
415
sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null)
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)
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()
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())
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)
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)
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)
308
# Actually delete the objects
442
# Actually delete the objects.
309
443
delete_objects(seen_objs)
311
445
delete.alters_data = True
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)
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)
328
460
except IndexError:
329
461
raise self.DoesNotExist, "%s matching query does not exist." % self.__class__._meta.object_name
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))]
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)
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))
350
def _get_FIELD_url(self, field):
351
if getattr(self, field.attname): # value is not blank
353
return urlparse.urljoin(settings.MEDIA_URL, getattr(self, field.attname)).replace('\\', '/')
356
def _get_FIELD_size(self, field):
357
return os.path.getsize(self._get_FIELD_filename(field))
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.
365
filename = field.get_filename(filename)
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)):
371
dot_index = filename.rindex('.')
372
except ValueError: # filename has no dot
375
filename = filename[:dot_index] + '_' + filename[dot_index:]
377
# Write the file to disk.
378
setattr(self, field.attname, filename)
380
full_filename = self._get_FIELD_filename(field)
381
fp = open(full_filename, 'wb')
382
fp.write(raw_contents)
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)
394
# Save the object because it has changed unless save is False
398
_save_FIELD_file.alters_data = True
400
def _get_FIELD_width(self, field):
401
return self._get_image_dimensions(field)[0]
403
def _get_FIELD_height(self, field):
404
return self._get_image_dimensions(field)[1]
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)
414
482
############################################
415
483
# HELPER FUNCTIONS (CURRIED MODEL METHODS) #
418
486
# ORDERING METHODS #########################
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()
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)]
443
506
##############################################
444
507
# HELPER FUNCTIONS (CURRIED MODEL FUNCTIONS) #
445
508
##############################################
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)
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,), {})
526
def subclass_exception(name, parent, module):
527
return type(name, (parent,), {'__module__': module})