Loading django/db/backends/sqlite3/schema.py +7 −5 Original line number Diff line number Diff line from django.db.backends.schema import BaseDatabaseSchemaEditor from django.db.models.loading import cache from django.db.models.loading import cache, default_cache, AppCache from django.db.models.fields.related import ManyToManyField Loading Loading @@ -46,10 +46,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): } meta = type("Meta", tuple(), meta_contents) body['Meta'] = meta body['__module__'] = "__fake__" with cache.temporary_state(): del cache.app_models[model._meta.app_label][model._meta.object_name.lower()] body['__module__'] = model.__module__ self.app_cache = AppCache() cache.set_cache(self.app_cache) cache.copy_from(default_cache) temp_model = type(model._meta.object_name, model.__bases__, body) cache.set_cache(default_cache) # Create a new table with that format self.create_model(temp_model) # Copy data from the old table Loading django/db/models/base.py +11 −8 Original line number Diff line number Diff line Loading @@ -228,14 +228,17 @@ class ModelBase(type): return new_class new_class._prepare() register_models(new_class._meta.app_label, new_class) if new_class._meta.auto_register: register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. return get_model(new_class._meta.app_label, name, seed_cache=False, only_installed=False) else: return new_class def copy_managers(cls, base_managers): # This is in-place sorting of an Options attribute, but that's fine. Loading django/db/models/loading.py +34 −54 Original line number Diff line number Diff line Loading @@ -236,69 +236,49 @@ class AppCache(object): model_dict[model_name] = model self._get_models_cache.clear() def save_state(self): """ Returns an object that contains the current AppCache state. Can be provided to restore_state to undo actions. """ return { "app_store": SortedDict(self.app_store.items()), "app_labels": dict(self.app_labels.items()), "app_models": SortedDict((k, SortedDict(v.items())) for k, v in self.app_models.items()), "app_errors": dict(self.app_errors.items()), } def restore_state(self, state): """ Restores the AppCache to a previous state from save_state. Note that the state is used by reference, not copied in. """ self.app_store = state['app_store'] self.app_labels = state['app_labels'] self.app_models = state['app_models'] self.app_errors = state['app_errors'] self._get_models_cache.clear() def copy_from(self, other): "Registers all models from the other cache into this one" cache._populate() for app_label, models in other.app_models.items(): self.register_models(app_label, *models.values()) def temporary_state(self): "Returns a context manager that restores the state on exit" return StateContextManager(self) def unregister_all(self): class AppCacheWrapper(object): """ Wipes the AppCache clean of all registered models. Used for things like migration libraries' fake ORMs. As AppCache can be changed at runtime, this class wraps it so any imported references to 'cache' are changed along with it. """ self.app_store = SortedDict() self.app_labels = {} self.app_models = SortedDict() self.app_errors = {} def __init__(self, cache): self._cache = cache class StateContextManager(object): """ Context manager for locking cache state. Useful for making temporary models you don't want to stay in the cache. """ def set_cache(self, cache): self._cache = cache def __init__(self, cache): self.cache = cache def __getattr__(self, attr): if attr in ("_cache", "set_cache"): return self.__dict__[attr] return getattr(self._cache, attr) def __enter__(self): self.state = self.cache.save_state() def __setattr__(self, attr, value): if attr in ("_cache", "set_cache"): self.__dict__[attr] = value return return setattr(self._cache, attr, value) def __exit__(self, type, value, traceback): self.cache.restore_state(self.state) default_cache = AppCache() cache = AppCacheWrapper(default_cache) cache = AppCache() # These methods were always module level, so are kept that way for backwards # compatibility. get_apps = cache.get_apps get_app = cache.get_app get_app_errors = cache.get_app_errors get_models = cache.get_models get_model = cache.get_model register_models = cache.register_models load_app = cache.load_app app_cache_ready = cache.app_cache_ready # compatibility. These are wrapped with lambdas to stop the attribute # access resolving directly to a method on a single cache instance. get_apps = lambda *x, **y: cache.get_apps(*x, **y) get_app = lambda *x, **y: cache.get_app(*x, **y) get_app_errors = lambda *x, **y: cache.get_app_errors(*x, **y) get_models = lambda *x, **y: cache.get_models(*x, **y) get_model = lambda *x, **y: cache.get_model(*x, **y) register_models = lambda *x, **y: cache.register_models(*x, **y) load_app = lambda *x, **y: cache.load_app(*x, **y) app_cache_ready = lambda *x, **y: cache.app_cache_ready(*x, **y) django/db/models/options.py +4 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]| DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering', 'unique_together', 'permissions', 'get_latest_by', 'order_with_respect_to', 'app_label', 'db_tablespace', 'abstract', 'managed', 'proxy', 'auto_created') 'abstract', 'managed', 'proxy', 'auto_created', 'auto_register') @python_2_unicode_compatible class Options(object): Loading Loading @@ -68,6 +68,9 @@ class Options(object): # from *other* models. Needed for some admin checks. Internal use only. self.related_fkey_lookups = [] # If we should auto-register with the AppCache self.auto_register = True def contribute_to_class(self, cls, name): from django.db import connection from django.db.backends.util import truncate_name Loading tests/modeltests/schema/models.py +8 −8 Original line number Diff line number Diff line Loading @@ -10,14 +10,14 @@ class Author(models.Model): height = models.PositiveIntegerField(null=True, blank=True) class Meta: managed = False auto_register = False class AuthorWithM2M(models.Model): name = models.CharField(max_length=255) class Meta: managed = False auto_register = False class Book(models.Model): Loading @@ -27,7 +27,7 @@ class Book(models.Model): #tags = models.ManyToManyField("Tag", related_name="books") class Meta: managed = False auto_register = False class BookWithM2M(models.Model): Loading @@ -37,7 +37,7 @@ class BookWithM2M(models.Model): tags = models.ManyToManyField("Tag", related_name="books") class Meta: managed = False auto_register = False class BookWithSlug(models.Model): Loading @@ -47,7 +47,7 @@ class BookWithSlug(models.Model): slug = models.CharField(max_length=20, unique=True) class Meta: managed = False auto_register = False db_table = "schema_book" Loading @@ -56,7 +56,7 @@ class Tag(models.Model): slug = models.SlugField(unique=True) class Meta: managed = False auto_register = False class TagUniqueRename(models.Model): Loading @@ -64,7 +64,7 @@ class TagUniqueRename(models.Model): slug2 = models.SlugField(unique=True) class Meta: managed = False auto_register = False db_table = "schema_tag" Loading @@ -73,5 +73,5 @@ class UniqueTest(models.Model): slug = models.SlugField(unique=False) class Meta: managed = False auto_register = False unique_together = ["year", "slug"] Loading
django/db/backends/sqlite3/schema.py +7 −5 Original line number Diff line number Diff line from django.db.backends.schema import BaseDatabaseSchemaEditor from django.db.models.loading import cache from django.db.models.loading import cache, default_cache, AppCache from django.db.models.fields.related import ManyToManyField Loading Loading @@ -46,10 +46,12 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): } meta = type("Meta", tuple(), meta_contents) body['Meta'] = meta body['__module__'] = "__fake__" with cache.temporary_state(): del cache.app_models[model._meta.app_label][model._meta.object_name.lower()] body['__module__'] = model.__module__ self.app_cache = AppCache() cache.set_cache(self.app_cache) cache.copy_from(default_cache) temp_model = type(model._meta.object_name, model.__bases__, body) cache.set_cache(default_cache) # Create a new table with that format self.create_model(temp_model) # Copy data from the old table Loading
django/db/models/base.py +11 −8 Original line number Diff line number Diff line Loading @@ -228,14 +228,17 @@ class ModelBase(type): return new_class new_class._prepare() register_models(new_class._meta.app_label, new_class) if new_class._meta.auto_register: register_models(new_class._meta.app_label, new_class) # Because of the way imports happen (recursively), we may or may not be # the first time this model tries to register with the framework. There # should only be one class for each model, so we always return the # registered version. return get_model(new_class._meta.app_label, name, seed_cache=False, only_installed=False) else: return new_class def copy_managers(cls, base_managers): # This is in-place sorting of an Options attribute, but that's fine. Loading
django/db/models/loading.py +34 −54 Original line number Diff line number Diff line Loading @@ -236,69 +236,49 @@ class AppCache(object): model_dict[model_name] = model self._get_models_cache.clear() def save_state(self): """ Returns an object that contains the current AppCache state. Can be provided to restore_state to undo actions. """ return { "app_store": SortedDict(self.app_store.items()), "app_labels": dict(self.app_labels.items()), "app_models": SortedDict((k, SortedDict(v.items())) for k, v in self.app_models.items()), "app_errors": dict(self.app_errors.items()), } def restore_state(self, state): """ Restores the AppCache to a previous state from save_state. Note that the state is used by reference, not copied in. """ self.app_store = state['app_store'] self.app_labels = state['app_labels'] self.app_models = state['app_models'] self.app_errors = state['app_errors'] self._get_models_cache.clear() def copy_from(self, other): "Registers all models from the other cache into this one" cache._populate() for app_label, models in other.app_models.items(): self.register_models(app_label, *models.values()) def temporary_state(self): "Returns a context manager that restores the state on exit" return StateContextManager(self) def unregister_all(self): class AppCacheWrapper(object): """ Wipes the AppCache clean of all registered models. Used for things like migration libraries' fake ORMs. As AppCache can be changed at runtime, this class wraps it so any imported references to 'cache' are changed along with it. """ self.app_store = SortedDict() self.app_labels = {} self.app_models = SortedDict() self.app_errors = {} def __init__(self, cache): self._cache = cache class StateContextManager(object): """ Context manager for locking cache state. Useful for making temporary models you don't want to stay in the cache. """ def set_cache(self, cache): self._cache = cache def __init__(self, cache): self.cache = cache def __getattr__(self, attr): if attr in ("_cache", "set_cache"): return self.__dict__[attr] return getattr(self._cache, attr) def __enter__(self): self.state = self.cache.save_state() def __setattr__(self, attr, value): if attr in ("_cache", "set_cache"): self.__dict__[attr] = value return return setattr(self._cache, attr, value) def __exit__(self, type, value, traceback): self.cache.restore_state(self.state) default_cache = AppCache() cache = AppCacheWrapper(default_cache) cache = AppCache() # These methods were always module level, so are kept that way for backwards # compatibility. get_apps = cache.get_apps get_app = cache.get_app get_app_errors = cache.get_app_errors get_models = cache.get_models get_model = cache.get_model register_models = cache.register_models load_app = cache.load_app app_cache_ready = cache.app_cache_ready # compatibility. These are wrapped with lambdas to stop the attribute # access resolving directly to a method on a single cache instance. get_apps = lambda *x, **y: cache.get_apps(*x, **y) get_app = lambda *x, **y: cache.get_app(*x, **y) get_app_errors = lambda *x, **y: cache.get_app_errors(*x, **y) get_models = lambda *x, **y: cache.get_models(*x, **y) get_model = lambda *x, **y: cache.get_model(*x, **y) register_models = lambda *x, **y: cache.register_models(*x, **y) load_app = lambda *x, **y: cache.load_app(*x, **y) app_cache_ready = lambda *x, **y: cache.app_cache_ready(*x, **y)
django/db/models/options.py +4 −1 Original line number Diff line number Diff line Loading @@ -21,7 +21,7 @@ get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]| DEFAULT_NAMES = ('verbose_name', 'verbose_name_plural', 'db_table', 'ordering', 'unique_together', 'permissions', 'get_latest_by', 'order_with_respect_to', 'app_label', 'db_tablespace', 'abstract', 'managed', 'proxy', 'auto_created') 'abstract', 'managed', 'proxy', 'auto_created', 'auto_register') @python_2_unicode_compatible class Options(object): Loading Loading @@ -68,6 +68,9 @@ class Options(object): # from *other* models. Needed for some admin checks. Internal use only. self.related_fkey_lookups = [] # If we should auto-register with the AppCache self.auto_register = True def contribute_to_class(self, cls, name): from django.db import connection from django.db.backends.util import truncate_name Loading
tests/modeltests/schema/models.py +8 −8 Original line number Diff line number Diff line Loading @@ -10,14 +10,14 @@ class Author(models.Model): height = models.PositiveIntegerField(null=True, blank=True) class Meta: managed = False auto_register = False class AuthorWithM2M(models.Model): name = models.CharField(max_length=255) class Meta: managed = False auto_register = False class Book(models.Model): Loading @@ -27,7 +27,7 @@ class Book(models.Model): #tags = models.ManyToManyField("Tag", related_name="books") class Meta: managed = False auto_register = False class BookWithM2M(models.Model): Loading @@ -37,7 +37,7 @@ class BookWithM2M(models.Model): tags = models.ManyToManyField("Tag", related_name="books") class Meta: managed = False auto_register = False class BookWithSlug(models.Model): Loading @@ -47,7 +47,7 @@ class BookWithSlug(models.Model): slug = models.CharField(max_length=20, unique=True) class Meta: managed = False auto_register = False db_table = "schema_book" Loading @@ -56,7 +56,7 @@ class Tag(models.Model): slug = models.SlugField(unique=True) class Meta: managed = False auto_register = False class TagUniqueRename(models.Model): Loading @@ -64,7 +64,7 @@ class TagUniqueRename(models.Model): slug2 = models.SlugField(unique=True) class Meta: managed = False auto_register = False db_table = "schema_tag" Loading @@ -73,5 +73,5 @@ class UniqueTest(models.Model): slug = models.SlugField(unique=False) class Meta: managed = False auto_register = False unique_together = ["year", "slug"]