diff options
| author | Christopher Long <indirecthit@gmail.com> | 2007-06-17 22:18:54 +0000 |
|---|---|---|
| committer | Christopher Long <indirecthit@gmail.com> | 2007-06-17 22:18:54 +0000 |
| commit | ae22b6d403dcf25098c77f0dfcf59ae58b186461 (patch) | |
| tree | c37fc631e99a7e4d909d6b6d236f495003731ea7 /django/db/models/base.py | |
| parent | 0cf7bc439129c66df8d64601e885f83b256b4f25 (diff) | |
per-object-permissions: Merged to trunk [5486] NOTE: Not fully tested, will be working on this over the next few weeks.
git-svn-id: http://code.djangoproject.com/svn/django/branches/per-object-permissions@5488 bcc190cf-cafb-0310-a4f2-bffc1f526a37
Diffstat (limited to 'django/db/models/base.py')
| -rw-r--r-- | django/db/models/base.py | 114 |
1 files changed, 77 insertions, 37 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py index 70569a2561..a8e6303e1c 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -13,6 +13,7 @@ from django.dispatch import dispatcher from django.utils.datastructures import SortedDict from django.utils.functional import curry from django.conf import settings +from itertools import izip import types import sys import os @@ -21,8 +22,13 @@ class ModelBase(type): "Metaclass for all models" def __new__(cls, name, bases, attrs): # If this isn't a subclass of Model, don't do anything special. - if not bases or bases == (object,): - return type.__new__(cls, name, bases, attrs) + try: + if not filter(lambda b: issubclass(b, Model), bases): + return super(ModelBase, cls).__new__(cls, name, bases, attrs) + except NameError: + # 'Model' isn't defined yet, meaning we're looking at Django's own + # Model class, defined below. + return super(ModelBase, cls).__new__(cls, name, bases, attrs) # Create the class. new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')}) @@ -36,11 +42,11 @@ class ModelBase(type): new_class._meta.parents.append(base) new_class._meta.parents.extend(base._meta.parents) - model_module = sys.modules[new_class.__module__] if getattr(new_class._meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. + model_module = sys.modules[new_class.__module__] new_class._meta.app_label = model_module.__name__.split('.')[-2] # Bail out early if we have already created this class. @@ -63,7 +69,7 @@ class ModelBase(type): if getattr(new_class._meta, 'row_level_permissions', False): from django.contrib.auth.models import RowLevelPermission - gen_rel = django.db.models.GenericRelation(RowLevelPermission, object_id_field="model_id", content_type_field="model_ct") + gen_rel = django.contrib.contenttypes.generic.GenericRelation(RowLevelPermission, object_id_field="model_id", content_type_field="model_ct") new_class.add_to_class("row_level_permissions", gen_rel) new_class._prepare() @@ -95,41 +101,74 @@ class Model(object): def __init__(self, *args, **kwargs): dispatcher.send(signal=signals.pre_init, sender=self.__class__, args=args, kwargs=kwargs) - for f in self._meta.fields: - if isinstance(f.rel, ManyToOneRel): - try: - # Assume object instance was passed in. - rel_obj = kwargs.pop(f.name) - except KeyError: + + # There is a rather weird disparity here; if kwargs, it's set, then args + # overrides it. It should be one or the other; don't duplicate the work + # The reason for the kwargs check is that standard iterator passes in by + # args, and nstantiation for iteration is 33% faster. + args_len = len(args) + if args_len > len(self._meta.fields): + # Daft, but matches old exception sans the err msg. + raise IndexError("Number of args exceeds number of fields") + + fields_iter = iter(self._meta.fields) + if not kwargs: + # The ordering of the izip calls matter - izip throws StopIteration + # when an iter throws it. So if the first iter throws it, the second + # is *not* consumed. We rely on this, so don't change the order + # without changing the logic. + for val, field in izip(args, fields_iter): + setattr(self, field.attname, val) + else: + # Slower, kwargs-ready version. + for val, field in izip(args, fields_iter): + setattr(self, field.attname, val) + kwargs.pop(field.name, None) + # Maintain compatibility with existing calls. + if isinstance(field.rel, ManyToOneRel): + kwargs.pop(field.attname, None) + + # Now we're left with the unprocessed fields that *must* come from + # keywords, or default. + + for field in fields_iter: + if kwargs: + if isinstance(field.rel, ManyToOneRel): try: - # Object instance wasn't passed in -- must be an ID. - val = kwargs.pop(f.attname) + # Assume object instance was passed in. + rel_obj = kwargs.pop(field.name) except KeyError: - val = f.get_default() - else: - # Object instance was passed in. - # Special case: You can pass in "None" for related objects if it's allowed. - if rel_obj is None and f.null: - val = None - else: try: - val = getattr(rel_obj, f.rel.get_related_field().attname) - except AttributeError: - raise TypeError, "Invalid value: %r should be a %s instance, not a %s" % (f.name, f.rel.to, type(rel_obj)) - setattr(self, f.attname, val) + # Object instance wasn't passed in -- must be an ID. + val = kwargs.pop(field.attname) + except KeyError: + val = field.get_default() + else: + # Object instance was passed in. Special case: You can + # pass in "None" for related objects if it's allowed. + if rel_obj is None and field.null: + val = None + else: + try: + val = getattr(rel_obj, field.rel.get_related_field().attname) + except AttributeError: + raise TypeError("Invalid value: %r should be a %s instance, not a %s" % + (field.name, field.rel.to, type(rel_obj))) + else: + val = kwargs.pop(field.attname, field.get_default()) else: - val = kwargs.pop(f.attname, f.get_default()) - setattr(self, f.attname, val) - for prop in kwargs.keys(): - try: - if isinstance(getattr(self.__class__, prop), property): - setattr(self, prop, kwargs.pop(prop)) - except AttributeError: - pass + val = field.get_default() + setattr(self, field.attname, val) + if kwargs: - raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] - for i, arg in enumerate(args): - setattr(self, self._meta.fields[i].attname, arg) + for prop in kwargs.keys(): + try: + if isinstance(getattr(self.__class__, prop), property): + setattr(self, prop, kwargs.pop(prop)) + except AttributeError: + pass + if kwargs: + raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] dispatcher.send(signal=signals.post_init, sender=self.__class__, instance=self) def add_to_class(cls, name, value): @@ -327,7 +366,7 @@ class Model(object): def _get_FIELD_size(self, field): return os.path.getsize(self._get_FIELD_filename(field)) - def _save_FIELD_file(self, field, filename, raw_contents): + def _save_FIELD_file(self, field, filename, raw_contents, save=True): directory = field.get_directory_name() try: # Create the date-based directory if it doesn't exist. os.makedirs(os.path.join(settings.MEDIA_ROOT, directory)) @@ -362,8 +401,9 @@ class Model(object): if field.height_field: setattr(self, field.height_field, height) - # Save the object, because it has changed. - self.save() + # Save the object because it has changed unless save is False + if save: + self.save() _save_FIELD_file.alters_data = True |
