Handling Unmanaged Models in Pytest-Django
The Challenge of Testing Unmanaged Models
In Django projects, we occasionally encounter unmanaged models—models that don’t have managed = True in their meta options. These models can make testing tricky, especially when your test setup involves a mix of managed and unmanaged models or multiple databases (e.g., one with managed models and another with unmanaged models).
This blog post explores approaches to testing unmanaged models with pytest-django, highlighting pros, cons, and workarounds to help you manage these scenarios effectively.
Approach 1: Mark All Models as Managed
One straightforward way to handle unmanaged models during testing is to temporarily mark them as managed. Here’s how you can do it:
# Add this to conftest.py @pytest.hookimpl(tryfirst=True) def pytest_runtestloop(): from django.apps import apps unmanaged_models = [] for app in apps.get_app_configs(): unmanaged_models += [m for m in app.get_models() if not m._meta.managed] for m in unmanaged_models: m._meta.managed = True
Note: For this approach to work, you need to add a --no-migrations option to your pytest settings (or pytest.ini)
Reference: Stack Overflow
Pros:
- Simple to implement.
Cons:
- Skips migration testing, which can cause issues when multiple developers are working on the same project.
Approach 2: Create Unmanaged Models Manually
Alternatively, you can manually create unmanaged models during the test setup. This approach ensures that migrations are tested:
@pytest.fixture(scope="session", autouse=True) def django_db_setup(django_db_blocker, django_db_setup): with django_db_blocker.unblock(): for _connection in connections.all(): with _connection.schema_editor() as schema_editor: setup_unmanaged_models(_connection, schema_editor) yield def setup_unmanaged_models(connection, schema_editor): from django.apps import apps unmanaged_models = [ model for model in apps.get_models() if model._meta.managed is False ] for model in unmanaged_models: if model._meta.db_table in connection.introspection.table_names(): schema_editor.delete_model(model) schema_editor.create_model(model)
Pros:
- Tests migrations as part of your test cases.
Cons:
- Slightly more complex.
- transaction=True doesn’t work with this approach (discussed in the next section).
Understanding Transactional Tests
Pytest-django provides a database fixture: django_db and django_db(transaction=True). Here’s how they differ:
django_db: Rolls back changes at the end of a test case, meaning no actual commit is made to the database.
django_db(transaction=True): Commits changes and truncates the database tables after each test case. Since only managed models are being truncated after every test, this is the reason unmanaged models require special handling during transactional tests.
Example Test Case
@pytest.mark.django_db def test_example(): # Test case logic here pass @pytest.mark.django_db(transaction=True) def test_transactional_example(): # Test case logic here pass
Making Transactional Tests Work with Unmanaged Models
Since transactional tests truncate only managed models, we can modify unmanaged models to be managed during the test run. This ensures they are included in truncation:
# Add this to conftest.py @pytest.hookimpl(tryfirst=True) def pytest_runtestloop(): from django.apps import apps unmanaged_models = [] for app in apps.get_app_configs(): unmanaged_models += [m for m in app.get_models() if not m._meta.managed] for m in unmanaged_models: m._meta.managed = True
Avoiding transaction=True with on_commit Hooks (iff possible)
In scenarios involving on_commit hooks, you can avoid using transactional tests by capturing and executing on_commit callbacks directly, using fixture django_capture_on_commit_callbacks from pytest-django(>= v.4.4):
@pytest.fixture(scope="session", autouse=True) def django_db_setup(django_db_blocker, django_db_setup): with django_db_blocker.unblock(): for _connection in connections.all(): with _connection.schema_editor() as schema_editor: setup_unmanaged_models(_connection, schema_editor) yield def setup_unmanaged_models(connection, schema_editor): from django.apps import apps unmanaged_models = [ model for model in apps.get_models() if model._meta.managed is False ] for model in unmanaged_models: if model._meta.db_table in connection.introspection.table_names(): schema_editor.delete_model(model) schema_editor.create_model(model)
References
- pytest-django Documentation
- Stack Overflow: Testing Unmanaged Models
Do you have other approaches or tips for handling unmanaged models? Share them in the comments below!
The above is the detailed content of Handling Unmanaged Models in Pytest-Django. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



Solution to permission issues when viewing Python version in Linux terminal When you try to view Python version in Linux terminal, enter python...

When using Python's pandas library, how to copy whole columns between two DataFrames with different structures is a common problem. Suppose we have two Dats...

How to teach computer novice programming basics within 10 hours? If you only have 10 hours to teach computer novice some programming knowledge, what would you choose to teach...

How to avoid being detected when using FiddlerEverywhere for man-in-the-middle readings When you use FiddlerEverywhere...

Regular expressions are powerful tools for pattern matching and text manipulation in programming, enhancing efficiency in text processing across various applications.

The article discusses popular Python libraries like NumPy, Pandas, Matplotlib, Scikit-learn, TensorFlow, Django, Flask, and Requests, detailing their uses in scientific computing, data analysis, visualization, machine learning, web development, and H

How does Uvicorn continuously listen for HTTP requests? Uvicorn is a lightweight web server based on ASGI. One of its core functions is to listen for HTTP requests and proceed...

In Python, how to dynamically create an object through a string and call its methods? This is a common programming requirement, especially if it needs to be configured or run...
