{"id":16417508,"url":"https://github.com/charettes/django-seal","last_synced_at":"2025-05-15T12:06:32.102Z","repository":{"id":28085975,"uuid":"116181134","full_name":"charettes/django-seal","owner":"charettes","description":"Django application providing queryset sealing capability.","archived":false,"fork":false,"pushed_at":"2025-05-14T15:22:49.000Z","size":252,"stargazers_count":257,"open_issues_count":6,"forks_count":6,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-05-14T15:47:54.804Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/charettes.png","metadata":{"files":{"readme":"README.rst","changelog":"CHANGELOG.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-03T20:55:54.000Z","updated_at":"2025-05-14T15:12:41.000Z","dependencies_parsed_at":"2025-02-15T06:13:23.020Z","dependency_job_id":"c635e36d-72da-456a-8580-829e0ea795c7","html_url":"https://github.com/charettes/django-seal","commit_stats":{"total_commits":156,"total_committers":5,"mean_commits":31.2,"dds":0.3141025641025641,"last_synced_commit":"a7eddb63891707897bcf24ec9d540c8befb8ef66"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charettes%2Fdjango-seal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charettes%2Fdjango-seal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charettes%2Fdjango-seal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/charettes%2Fdjango-seal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/charettes","download_url":"https://codeload.github.com/charettes/django-seal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254190396,"owners_count":22029632,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T07:11:32.934Z","updated_at":"2025-05-15T12:06:27.088Z","avatar_url":"https://github.com/charettes.png","language":"Python","readme":"django-seal\n===========\n\n.. image:: https://publicdomainvectors.org/photos/Seal2.png\n    :target: https://publicdomainvectors.org\n    :alt: Seal\n\n------------\n\n.. image:: https://github.com/charettes/django-seal/workflows/Test/badge.svg\n    :target: https://github.com/charettes/django-seal/actions\n    :alt: Build Status\n\n.. image:: https://coveralls.io/repos/github/charettes/django-seal/badge.svg?branch=master\n    :target: https://coveralls.io/github/charettes/django-seal?branch=master\n    :alt: Coverage status\n\n\nDjango application providing queryset sealing capability to force appropriate usage of ``only()``/``defer()`` and\n``select_related()``/``prefetch_related()``.\n\nInstallation\n------------\n\n.. code:: sh\n\n    pip install django-seal\n\nUsage\n-----\n\n.. code:: python\n\n    # models.py\n    from django.db import models\n    from seal.models import SealableModel\n\n    class Location(SealableModel):\n        latitude = models.FloatField()\n        longitude = models.FloatField()\n\n    class SeaLion(SealableModel):\n        height = models.PositiveIntegerField()\n        weight = models.PositiveIntegerField()\n        location = models.ForeignKey(Location, models.CASCADE, null=True)\n        previous_locations = models.ManyToManyField(Location, related_name='previous_visitors')\n\nBy default ``UnsealedAttributeAccess`` warnings will be raised on sealed objects attributes accesses\n\n.. code:: python\n\n    \u003e\u003e\u003e location = Location.objects.create(latitude=51.585474, longitude=156.634331)\n    \u003e\u003e\u003e sealion = SeaLion.objects.create(height=1, weight=100, location=location)\n    \u003e\u003e\u003e sealion.previous_locations.add(location)\n    \u003e\u003e\u003e SeaLion.objects.only('height').seal().get().weight\n    UnsealedAttributeAccess:: Attempt to fetch deferred field \"weight\" on sealed \u003cSeaLion instance\u003e.\n    \u003e\u003e\u003e SeaLion.objects.seal().get().location\n    UnsealedAttributeAccess: Attempt to fetch related field \"location\" on sealed \u003cSeaLion instance\u003e.\n    \u003e\u003e\u003e SeaLion.objects.seal().get().previous_locations.all()\n    UnsealedAttributeAccess: Attempt to fetch many-to-many field \"previous_locations\" on sealed \u003cSeaLion instance\u003e.\n\nYou can `elevate the warnings to exceptions by filtering them`_. This is useful to assert no unsealed attribute accesses are\nperformed when running your test suite for example.\n\n.. code:: python\n\n    \u003e\u003e\u003e import warnings\n    \u003e\u003e\u003e from seal.exceptions import UnsealedAttributeAccess\n    \u003e\u003e\u003e warnings.filterwarnings('error', category=UnsealedAttributeAccess)\n    \u003e\u003e\u003e SeaLion.objects.only('height').seal().get().weight\n    Traceback (most recent call last)\n    ...\n    UnsealedAttributeAccess:: Attempt to fetch deferred field \"weight\" on sealed \u003cSeaLion instance\u003e.\n    \u003e\u003e\u003e SeaLion.objects.seal().get().location\n    Traceback (most recent call last)\n    ...\n    UnsealedAttributeAccess: Attempt to fetch related field \"location\" on sealed \u003cSeaLion instance\u003e.\n    \u003e\u003e\u003e SeaLion.objects.seal().get().previous_locations.all()\n    Traceback (most recent call last)\n    ...\n    UnsealedAttributeAccess: Attempt to fetch many-to-many field \"previous_locations\" on sealed \u003cSeaLion instance\u003e.\n\nOr you can `configure logging to capture warnings`_ to log unsealed attribute accesses to the ``py.warnings`` logger which is a\nnice way to identify and address unsealed attributes accesses from production logs without taking your application down if some\ninstances happen to slip through your battery of tests.\n\n.. code:: python\n\n    \u003e\u003e\u003e import logging\n    \u003e\u003e\u003e logging.captureWarnings(True)\n\n.. _elevate the warnings to exceptions by filtering them: https://docs.python.org/3/library/warnings.html#warnings.filterwarnings\n.. _configure logging to capture warnings: https://docs.python.org/3/library/logging.html#logging.captureWarnings\n\nSealable managers can also be automatically sealed at model definition time to avoid having to call ``seal()`` systematically\nby passing ``seal=True`` to ``SealableModel`` subclasses, ``SealableManager`` and ``SealableQuerySet.as_manager``.\n\n.. code-block:: python\n\n    from django.db import models\n    from seal.models import SealableManager, SealableModel, SealableQuerySet\n\n    class Location(SealableModel, seal=True):\n        latitude = models.FloatField()\n        longitude = models.FloatField()\n\n    class SeaLion(SealableModel):\n        height = models.PositiveIntegerField()\n        weight = models.PositiveIntegerField()\n        location = models.ForeignKey(Location, models.CASCADE, null=True)\n        previous_locations = models.ManyToManyField(Location, related_name='previous_visitors')\n\n        objects = SealableManager(seal=True)\n        others = SealableQuerySet.as_manager(seal=True)\n\nDevelopment\n-----------\n\nMake your changes, and then run tests via tox:\n\n.. code:: sh\n\n    tox\n","funding_links":[],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharettes%2Fdjango-seal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcharettes%2Fdjango-seal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcharettes%2Fdjango-seal/lists"}