def test_unavailable_site_model(self): """ #24075 - A Site shouldn't be created if the model isn't available. """ apps = Apps() create_default_site(self.app_config, verbosity=0, apps=apps) self.assertFalse(Site.objects.exists())
def test_ready(self): """ Tests the ready property of the master registry. """ # The master app registry is always ready when the tests run. self.assertIs(apps.ready, True) # Non-master app registries are populated in __init__. self.assertIs(Apps().ready, True)
class M(models.Model): foo = models.IntegerField() bar = models.IntegerField() baz = models.IntegerField() Meta = type('Meta', (), { 'unique_together': unique_together, 'apps': Apps() })
def test_register_model_class_senders_immediately(self): """ Model signals registered with model classes as senders don't use the Apps.lazy_model_operation() mechanism. """ # Book isn't registered with apps2, so it will linger in # apps2._pending_operations if ModelSignal does the wrong thing. apps2 = Apps() signals.post_init.connect(self.receiver, sender=Book, apps=apps2) self.assertEqual(list(apps2._pending_operations), [])
def test_dynamic_load(self): """ Makes a new model at runtime and ensures it goes into the right place. """ old_models = list(apps.get_app_config("apps").get_models()) # Construct a new model in a new app registry body = {} new_apps = Apps(["apps"]) meta_contents = { 'app_label': "apps", 'apps': new_apps, } meta = type("Meta", (), meta_contents) body['Meta'] = meta body['__module__'] = TotallyNormal.__module__ temp_model = type("SouthPonies", (models.Model,), body) # Make sure it appeared in the right place! self.assertEqual(list(apps.get_app_config("apps").get_models()), old_models) with self.assertRaises(LookupError): apps.get_model("apps", "SouthPonies") self.assertEqual(new_apps.get_model("apps", "SouthPonies"), temp_model)
def test_model_clash(self): """ Test for behavior when two models clash in the app registry. """ new_apps = Apps(["apps"]) meta_contents = { 'app_label': "apps", 'apps': new_apps, } body = {} body['Meta'] = type("Meta", (), meta_contents) body['__module__'] = TotallyNormal.__module__ type("SouthPonies", (models.Model,), body) # When __name__ and __module__ match we assume the module # was reloaded and issue a warning. This use-case is # useful for REPL. Refs #23621. body = {} body['Meta'] = type("Meta", (), meta_contents) body['__module__'] = TotallyNormal.__module__ msg = ( "Model 'apps.southponies' was already registered. " "Reloading models is not advised as it can lead to inconsistencies, " "most notably with related models." ) with self.assertRaisesMessage(RuntimeWarning, msg): type("SouthPonies", (models.Model,), body) # If it doesn't appear to be a reloaded module then we expect # a RuntimeError. body = {} body['Meta'] = type("Meta", (), meta_contents) body['__module__'] = TotallyNormal.__module__ + '.whatever' with self.assertRaisesMessage(RuntimeError, "Conflicting 'southponies' models in application 'apps':"): type("SouthPonies", (models.Model,), body)
def enable(self): self.old_apps = Options.default_apps apps = Apps(self.installed_apps) setattr(Options, 'default_apps', apps) return apps
def test_singleton_master(self): """ Only one master registry can exist. """ with self.assertRaises(RuntimeError): Apps(installed_apps=None)
def test_unavailable_content_type_model(self): """A ContentType isn't created if the model isn't available.""" apps = Apps() with self.assertNumQueries(0): contenttypes_management.create_contenttypes(self.app_config, interactive=False, verbosity=0, apps=apps) self.assertEqual(ContentType.objects.count(), self.before_count + 1)
from djmodels.apps.registry import Apps from djmodels.db import models # Because we want to test creation and deletion of these as separate things, # these models are all inserted into a separate Apps so the main test # runner doesn't migrate them. new_apps = Apps() class Author(models.Model): name = models.CharField(max_length=255) height = models.PositiveIntegerField(null=True, blank=True) weight = models.IntegerField(null=True, blank=True) uuid = models.UUIDField(null=True) class Meta: apps = new_apps class AuthorCharFieldWithIndex(models.Model): char_field = models.CharField(max_length=31, db_index=True) class Meta: apps = new_apps class AuthorTextFieldWithIndex(models.Model): text_field = models.TextField(db_index=True) class Meta:
def _remake_table(self, model, create_field=None, delete_field=None, alter_field=None, add_constraint=None, remove_constraint=None): """ Shortcut to transform a model from old_model into new_model The essential steps are: 1. rename the model's existing table, e.g. "app_model" to "app_model__old" 2. create a table with the updated definition called "app_model" 3. copy the data from the old renamed table to the new table 4. delete the "app_model__old" table """ # Self-referential fields must be recreated rather than copied from # the old model to ensure their remote_field.field_name doesn't refer # to an altered field. def is_self_referential(f): return f.is_relation and f.remote_field.model is model # Work out the new fields dict / mapping body = { f.name: f.clone() if is_self_referential(f) else f for f in model._meta.local_concrete_fields } # Since mapping might mix column names and default values, # its values must be already quoted. mapping = { f.column: self.quote_name(f.column) for f in model._meta.local_concrete_fields } # This maps field names (not columns) for things like unique_together rename_mapping = {} # If any of the new or altered fields is introducing a new PK, # remove the old one restore_pk_field = None if getattr(create_field, 'primary_key', False) or ( alter_field and getattr(alter_field[1], 'primary_key', False)): for name, field in list(body.items()): if field.primary_key: field.primary_key = False restore_pk_field = field if field.auto_created: del body[name] del mapping[field.column] # Add in any created fields if create_field: body[create_field.name] = create_field # Choose a default and insert it into the copy map if not create_field.many_to_many and create_field.concrete: mapping[create_field.column] = self.quote_value( self.effective_default(create_field)) # Add in any altered fields if alter_field: old_field, new_field = alter_field body.pop(old_field.name, None) mapping.pop(old_field.column, None) body[new_field.name] = new_field if old_field.null and not new_field.null: case_sql = "coalesce(%(col)s, %(default)s)" % { 'col': self.quote_name(old_field.column), 'default': self.quote_value( self.effective_default(new_field)) } mapping[new_field.column] = case_sql else: mapping[new_field.column] = self.quote_name(old_field.column) rename_mapping[old_field.name] = new_field.name # Remove any deleted fields if delete_field: del body[delete_field.name] del mapping[delete_field.column] # Remove any implicit M2M tables if delete_field.many_to_many and delete_field.remote_field.through._meta.auto_created: return self.delete_model(delete_field.remote_field.through) # Work inside a new app registry apps = Apps() # Provide isolated instances of the fields to the new model body so # that the existing model's internals aren't interfered with when # the dummy model is constructed. body = copy.deepcopy(body) # Work out the new value of unique_together, taking renames into # account unique_together = [[rename_mapping.get(n, n) for n in unique] for unique in model._meta.unique_together] # Work out the new value for index_together, taking renames into # account index_together = [[rename_mapping.get(n, n) for n in index] for index in model._meta.index_together] indexes = model._meta.indexes if delete_field: indexes = [ index for index in indexes if delete_field.name not in index.fields ] constraints = list(model._meta.constraints) if add_constraint: constraints.append(add_constraint) if remove_constraint: constraints = [ constraint for constraint in constraints if remove_constraint.name != constraint.name ] # Construct a new model for the new state meta_contents = { 'app_label': model._meta.app_label, 'db_table': model._meta.db_table, 'unique_together': unique_together, 'index_together': index_together, 'indexes': indexes, 'constraints': constraints, 'apps': apps, } meta = type("Meta", (), meta_contents) body['Meta'] = meta body['__module__'] = model.__module__ temp_model = type(model._meta.object_name, model.__bases__, body) # We need to modify model._meta.db_table, but everything explodes # if the change isn't reversed before the end of this method. This # context manager helps us avoid that situation. @contextlib.contextmanager def altered_table_name(model, temporary_table_name): original_table_name = model._meta.db_table model._meta.db_table = temporary_table_name yield model._meta.db_table = original_table_name with altered_table_name(model, model._meta.db_table + "__old"): # Rename the old table to make way for the new self.alter_db_table( model, temp_model._meta.db_table, model._meta.db_table, disable_constraints=False, ) # Create a new table with the updated schema. self.create_model(temp_model) # Copy data from the old table into the new table field_maps = list(mapping.items()) self.execute("INSERT INTO %s (%s) SELECT %s FROM %s" % ( self.quote_name(temp_model._meta.db_table), ', '.join(self.quote_name(x) for x, y in field_maps), ', '.join(y for x, y in field_maps), self.quote_name(model._meta.db_table), )) # Delete the old table self.delete_model(model, handle_autom2m=False) # Run deferred SQL on correct table for sql in self.deferred_sql: self.execute(sql) self.deferred_sql = [] # Fix any PK-removed field if restore_pk_field: restore_pk_field.primary_key = True
class Meta: apps = Apps() app_label = "migrations" db_table = "django_migrations"
from djmodels.apps.registry import Apps from djmodels.db import models # We're testing app registry presence on load, so this is handy. new_apps = Apps(['apps']) class TotallyNormal(models.Model): name = models.CharField(max_length=255) class SoAlternative(models.Model): name = models.CharField(max_length=255) class Meta: apps = new_apps
class Meta: # Disable auto loading of this model as we load it on our own apps = Apps()
class Meta: # Disable auto loading of this model as we load it on our own apps = Apps() verbose_name = 'úñí©óðé µóðéø' verbose_name_plural = 'úñí©óðé µóðéøß'