Hi everyone! I'd like to get your thoughts on something.
Unmanaged models mean that Django no longer handles creating and managing schema at the database level (hence the name). When running tests, this means these tables aren't created, and we can't run queries against that model. The general solution I found is to monkey-patch the TestSuiteRunner to temporarily treat models as managed <https://www.caktusgroup.com/blog/2010/09/24/simplifying-the-testing-of-unmanaged-database-models-in-django/> . Doing a bit of research I however came up with a solution using SchemaEditor <https://docs.djangoproject.com/en/5.0/ref/schema-editor/>, to create the model tables directly, viz: ``` """ A cleaner approach to temporarily creating unmanaged model db tables for tests """ from unittest import TestCase from django.db import connections, models class create_unmanaged_model_tables: """ Create db tables for unmanaged models for tests Adapted from: https://stackoverflow.com/a/49800437 Examples: with create_unmanaged_model_tables(UnmanagedModel): ... @create_unmanaged_model_tables(UnmanagedModel, FooModel) def test_generate_data(): ... @create_unmanaged_model_tables(UnmanagedModel, FooModel) def MyTestCase(unittest.TestCase): ... """ def __init__(self, unmanaged_models: list[ModelBase], db_alias: str = "default"): """ :param str db_alias: Name of the database to connect to, defaults to "default" """ self.unmanaged_models = unmanaged_models self.db_alias = db_alias self.connection = connections[db_alias] def __call__(self, obj): if issubclass(obj, TestCase): return self.decorate_class(obj) return self.decorate_callable(obj) def __enter__(self): self.start() def __exit__(self, exc_type, exc_value, traceback): self.stop() def start(self): with self.connection.schema_editor() as schema_editor: for model in self.unmanaged_models: schema_editor.create_model(model) if ( model._meta.db_table not in self.connection.introspection.table_names() ): raise ValueError( "Table `{table_name}` is missing in test database.".format( table_name=model._meta.db_table ) ) def stop(self): with self.connection.schema_editor() as schema_editor: for model in self.unmanaged_models: schema_editor.delete_model(model) def copy(self): return self.__class__( unmanaged_models=self.unmanaged_models, db_alias=self.db_alias ) def decorate_class(self, klass): # Modify setUpClass and tearDownClass orig_setUpClass = klass.setUpClass orig_tearDownClass = klass.tearDownClass @classmethod def setUpClass(cls): self.start() if orig_setUpClass is not None: orig_setUpClass() @classmethod def tearDownClass(cls): if orig_tearDownClass is not None: orig_tearDownClass() self.stop() klass.setUpClass = setUpClass klass.tearDownClass = tearDownClass return klass def decorate_callable(self, callable_obj): @functools.wraps(callable_obj) def wrapper(*args, **kwargs): with self.copy(): return callable_obj(*args, **kwargs) return wrapper ``` Would this make a good addition to *django.test.utils*? P.S: First time posting here :P -- You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/6f5c668b-8f72-42be-9e41-01c786c12027n%40googlegroups.com.