summaryrefslogtreecommitdiff
path: root/django/db/models/base.py
diff options
context:
space:
mode:
authorChristopher Long <indirecthit@gmail.com>2007-06-17 22:18:54 +0000
committerChristopher Long <indirecthit@gmail.com>2007-06-17 22:18:54 +0000
commitae22b6d403dcf25098c77f0dfcf59ae58b186461 (patch)
treec37fc631e99a7e4d909d6b6d236f495003731ea7 /django/db/models/base.py
parent0cf7bc439129c66df8d64601e885f83b256b4f25 (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.py114
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