Django application providing queryset sealing capability to force appropriate usage of only()/defer() and select_related()/prefetch_related().
Installation
pip install django-seal
Add 'seal' to your INSTALLED_APPS
# settings.py
INSTALLED_APPS = [
...
'seal',
...
]
Usage
# models.py
from django.db import models
from seal.models import SealableModel
class Location(SealableModel):
latitude = models.FloatField()
longitude = models.FloatField()
class SeaLion(SealableModel):
height = models.PositiveIntegerField()
weight = models.PositiveIntegerField()
location = models.ForeignKey(Location, models.CASCADE, null=True)
previous_locations = models.ManyToManyField(Location, related_name='previous_visitors')
By default UnsealedAttributeAccess warnings will be raised on sealed objects attributes accesses
>>> location = Location.objects.create(latitude=51.585474, longitude=156.634331)
>>> sealion = SeaLion.objects.create(height=1, weight=100, location=location)
>>> sealion.previous_locations.add(location)
>>> SeaLion.objects.only('height').seal().get().weight
UnsealedAttributeAccess:: Attempt to fetch deferred field "weight" on sealed <SeaLion instance>.
>>> SeaLion.objects.seal().get().location
UnsealedAttributeAccess: Attempt to fetch related field "location" on sealed <SeaLion instance>.
>>> SeaLion.objects.seal().get().previous_locations.all()
UnsealedAttributeAccess: Attempt to fetch many-to-many field "previous_locations" on sealed <SeaLion instance>.
You can elevate the warnings to exceptions by filtering them. This is useful to assert no unsealed attribute accesses are performed when running your test suite for example.
>>> import warnings
>>> from seal.exceptions import UnsealedAttributeAccess
>>> warnings.filterwarnings('error', category=UnsealedAttributeAccess)
>>> SeaLion.objects.only('height').seal().get().weight
Traceback (most recent call last)
...
UnsealedAttributeAccess:: Attempt to fetch deferred field "weight" on sealed <SeaLion instance>.
>>> SeaLion.objects.seal().get().location
Traceback (most recent call last)
...
UnsealedAttributeAccess: Attempt to fetch related field "location" on sealed <SeaLion instance>.
>>> SeaLion.objects.seal().get().previous_locations.all()
Traceback (most recent call last)
...
UnsealedAttributeAccess: Attempt to fetch many-to-many field "previous_locations" on sealed <SeaLion instance>.
Or you can configure logging to capture warnings to log unsealed attribute accesses to the py.warnings logger which is a nice way to identify and address unsealed attributes accesses from production logs without taking your application down if some instances happen to slip through your battery of tests.
>>> import logging
>>> logging.captureWarnings(True)
Sealable managers can also be automatically sealed at model definition time to avoid having to call seal() systematically by passing seal=True to SealableModel subclasses, SealableManager and SealableQuerySet.as_manager.
from django.db import models
from seal.models import SealableManager, SealableModel, SealableQuerySet
class Location(SealableModel, seal=True):
latitude = models.FloatField()
longitude = models.FloatField()
class SeaLion(SealableModel):
height = models.PositiveIntegerField()
weight = models.PositiveIntegerField()
location = models.ForeignKey(Location, models.CASCADE, null=True)
previous_locations = models.ManyToManyField(Location, related_name='previous_visitors')
objects = SealableManager(seal=True)
others = SealableQuerySet.as_manager(seal=True)
Development
Make your changes, and then run tests via tox:
tox
Metadata
Release files for django-seal 1.7.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_seal-1.7.1.tar.gz | 13.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_seal-1.7.1-py2.py3-none-any.whl | Python 3, Python 2 | none | any | Details |
Total release size: 23.6 kB
Release files / django_seal-1.7.1.tar.gz
| Download URL | django_seal-1.7.1.tar.gz |
|---|---|
| Size | 13.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e850fbbc1023780f7dae1599839459d8e818979ceecbe9f73d4a53ccb72fadbd
|
|
BLAKE2b-256 checksum How to use checksums |
950aad6cab11f8bf4a4273578c8d9a76cac52e6c476b8f06135c7b8a29ca9316
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Release files / django_seal-1.7.1-py2.py3-none-any.whl
| Download URL | django_seal-1.7.1-py2.py3-none-any.whl |
|---|---|
| Size | 9.9 kB |
| Tags | Python 2 Python 3 |
|
SHA-256 checksum How to use checksums |
4b4670c9d0b59ffbeb5432a85cc9cc1d26ebfda1b946aa695f725c5e30f63cc3
|
|
BLAKE2b-256 checksum How to use checksums |
17e64f7aee0c942982fe4046805944c00bd33ea9f4bbd32048c6a81e762c897d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|