Swapper
Swapper is an unofficial API for Django's powerful but undocumented swappable models feature. It facilitates implementing arbitrary swappable models in reusable Django applications, akin to how `auth.User` is swappable. The library is actively maintained by the OpenWISP project with a moderate release cadence, with the latest major version being 1.4.0.
Warnings
- gotcha Do not use `swapper.load_model()` before the Django model system has fully initialized (e.g., at module level in `models.py`). It behaves similarly to `django.contrib.auth.get_user_model()` and should be called after models are ready.
- breaking Migrating from a non-swapped model implementation to a swapped one after initial migrations have been created for the non-swapped model is difficult and generally discouraged. Django's migration system makes assumptions that make this transition problematic.
- breaking Swapper v1.4.0 dropped support for Python 3.7. Applications running on Python 3.7 will need to use an older version of swapper (v1.3.0 or earlier) or upgrade their Python environment.
- breaking Swapper v1.4.0 dropped support for Django 4.0a1. While this was an alpha release, any applications still using this specific Django version will experience issues.
- gotcha When using `swapper.dependency()` in migrations, avoid `version='__latest__'` as it can lead to issues if new migrations are added to the depended module, potentially causing unexpected behavior or broken dependencies.
- gotcha When using multi-table inheritance with swappable models, ensure that any explicitly declared fields (especially those mimicking Django's auto-generated `_ptr` fields for parent links) do not clash with Django's automatically generated field names. This can lead to `FieldError` exceptions.
Install
-
pip install swapper
Imports
- swapper
import swapper
- load_model
from swapper import load_model
- swappable_setting
from swapper import swappable_setting
- dependency
from swapper import dependency
- get_model_name
from swapper import get_model_name
Quickstart
import swapper
from django.db import models
# reusableapp/models.py
class BaseParent(models.Model):
name = models.CharField(max_length=255)
class Meta:
abstract = True
class Parent(BaseParent):
class Meta:
swappable = swapper.swappable_setting('reusableapp', 'Parent')
class BaseChild(models.Model):
parent = models.ForeignKey(
swapper.get_model_name('reusableapp', 'Parent'),
on_delete=models.CASCADE
)
class Meta:
abstract = True
class Child(BaseChild):
class Meta:
swappable = swapper.swappable_setting('reusableapp', 'Child')
# reusableapp/views.py (or any other module needing the model)
# Always use swapper.load_model() instead of direct imports
ParentModel = swapper.load_model('reusableapp', 'Parent')
ChildModel = swapper.load_model('reusableapp', 'Child')
def get_all_parents():
return ParentModel.objects.all()