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