Ensure swapped models can't be queried.

This commit is contained in:
Russell Keith-Magee 2012-09-15 19:59:49 +08:00
parent 57ac6e3d32
commit 5d7bb22e8d
2 changed files with 15 additions and 5 deletions

View File

@ -13,7 +13,7 @@ def ensure_default_manager(sender, **kwargs):
_default_manager if it's not a subclass of Manager). _default_manager if it's not a subclass of Manager).
""" """
cls = sender cls = sender
if cls._meta.abstract: if cls._meta.abstract or cls._meta.swapped:
return return
if not getattr(cls, '_default_manager', None): if not getattr(cls, '_default_manager', None):
# Create the default manager, if needed. # Create the default manager, if needed.
@ -42,6 +42,7 @@ def ensure_default_manager(sender, **kwargs):
signals.class_prepared.connect(ensure_default_manager) signals.class_prepared.connect(ensure_default_manager)
class Manager(object): class Manager(object):
# Tracks each time a Manager instance is created. Used to retain order. # Tracks each time a Manager instance is created. Used to retain order.
creation_counter = 0 creation_counter = 0
@ -56,7 +57,9 @@ class Manager(object):
def contribute_to_class(self, model, name): def contribute_to_class(self, model, name):
# TODO: Use weakref because of possible memory leak / circular reference. # TODO: Use weakref because of possible memory leak / circular reference.
self.model = model self.model = model
setattr(model, name, ManagerDescriptor(self)) # Only contribute the manager if the model is concrete
if not model._meta.abstract and not model._meta.swapped:
setattr(model, name, ManagerDescriptor(self))
if not getattr(model, '_default_manager', None) or self.creation_counter < model._default_manager.creation_counter: if not getattr(model, '_default_manager', None) or self.creation_counter < model._default_manager.creation_counter:
model._default_manager = self model._default_manager = self
if model._meta.abstract or (self._inherited and not self.model._meta.proxy): if model._meta.abstract or (self._inherited and not self.model._meta.proxy):
@ -208,6 +211,7 @@ class Manager(object):
def raw(self, raw_query, params=None, *args, **kwargs): def raw(self, raw_query, params=None, *args, **kwargs):
return RawQuerySet(raw_query=raw_query, model=self.model, params=params, using=self._db, *args, **kwargs) return RawQuerySet(raw_query=raw_query, model=self.model, params=params, using=self._db, *args, **kwargs)
class ManagerDescriptor(object): class ManagerDescriptor(object):
# This class ensures managers aren't accessible via model instances. # This class ensures managers aren't accessible via model instances.
# For example, Poll.objects works, but poll_obj.objects raises AttributeError. # For example, Poll.objects works, but poll_obj.objects raises AttributeError.
@ -219,6 +223,7 @@ class ManagerDescriptor(object):
raise AttributeError("Manager isn't accessible via %s instances" % type.__name__) raise AttributeError("Manager isn't accessible via %s instances" % type.__name__)
return self.manager return self.manager
class EmptyManager(Manager): class EmptyManager(Manager):
def get_query_set(self): def get_query_set(self):
return self.get_empty_query_set() return self.get_empty_query_set()

View File

@ -222,10 +222,15 @@ class Options(object):
def _swapped(self): def _swapped(self):
""" """
Has this model been swapped out for another? Has this model been swapped out for another? If so, return the model
name of the replacement; otherwise, return None.
""" """
model_label = '%s.%s' % (self.app_label, self.object_name) if self.swappable:
return self.swappable and getattr(settings, self.swappable, None) not in (None, model_label) model_label = '%s.%s' % (self.app_label, self.object_name)
swapped_for = getattr(settings, self.swappable, None)
if swapped_for not in (None, model_label):
return swapped_for
return None
swapped = property(_swapped) swapped = property(_swapped)
def _fields(self): def _fields(self):