Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion seal/managers.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class SealedModelIterable(models.query.ModelIterable):
def __iter__(self):
objs = super(SealedModelIterable, self).__iter__()
for obj in objs:
obj._state.sealed = True
obj.seal()
yield obj


Expand Down
3 changes: 3 additions & 0 deletions seal/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ def __new__(cls, name, bases, attrs):
class SealableModel(with_metaclass(SealaleModelBase, models.Model)):
objects = SealableQuerySet.as_manager()

def seal(self):
self._state.sealed = True

class Meta:
abstract = True

Expand Down
8 changes: 8 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from django.db import models
from seal.managers import SealableQuerySet
from seal.models import SealableModel


Expand All @@ -17,3 +18,10 @@ class SeaLion(SealableModel):
class GreatSeaLion(SeaLion):
# TODO: add support for auto-generated o2os parent_link and non-parent link o2o.
sealion_ptr = models.OneToOneField(SeaLion, models.CASCADE, parent_link=True, primary_key=True)


class Koala(models.Model):
height = models.PositiveIntegerField()
weight = models.PositiveIntegerField()

objects = SealableQuerySet.as_manager()
7 changes: 6 additions & 1 deletion tests/test_managers.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from django.test import TestCase
from seal.exceptions import SealedObject

from .models import GreatSeaLion, Location, SeaLion
from .models import GreatSeaLion, Koala, Location, SeaLion


class SealableQuerySetTests(TestCase):
@classmethod
def setUpTestData(cls):
cls.location = Location.objects.create(latitude=51.585474, longitude=156.634331)
cls.great_sealion = GreatSeaLion.objects.create(height=1, weight=100, location=cls.location)
cls.koala = Koala.objects.create(height=1, weight=10)
cls.sealion = cls.great_sealion.sealion_ptr
cls.sealion.previous_locations.add(cls.location)

Expand Down Expand Up @@ -106,3 +107,7 @@ def test_not_reverse_sealed_many_to_many(self):
def test_sealed_prefetched_reverse_many_to_many(self):
instance = Location.objects.prefetch_related('previous_visitors').seal().get()
self.assertSequenceEqual(instance.previous_visitors.all(), [self.sealion])

def test_improper_usage_raises_error(self):
with self.assertRaises(AttributeError):
Koala.objects.only('pk').seal().get()
14 changes: 7 additions & 7 deletions tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,49 +7,49 @@
class SealableModelTests(SimpleTestCase):
def test_sealed_instance_deferred_attribute_access(self):
instance = SeaLion.from_db('default', ['id'], [1])
instance._state.sealed = True
instance.seal()
message = "Cannot fetch deferred fields weight on a sealed object."
with self.assertRaisesMessage(SealedObject, message):
instance.weight

def test_sealed_instance_foreign_key_access(self):
instance = SeaLion.from_db('default', ['id', 'location_id'], [1, 1])
instance._state.sealed = True
instance.seal()
message = "Cannot fetch related field location on a sealed object."
with self.assertRaisesMessage(SealedObject, message):
instance.location

def test_sealed_instance_reverse_foreign_key_access(self):
instance = Location.from_db('default', ['id'], [1])
instance._state.sealed = True
instance.seal()
message = "Cannot fetch many-to-many field visitors on a sealed object."
with self.assertRaisesMessage(SealedObject, message):
instance.visitors.all()

def test_sealed_instance_parent_link_access(self):
instance = SeaLion.from_db('default', ['id'], [1])
instance._state.sealed = True
instance.seal()
message = "Cannot fetch related field greatsealion on a sealed object."
with self.assertRaisesMessage(SealedObject, message):
instance.greatsealion

def test_sealed_instance_reverse_parent_link_access(self):
instance = GreatSeaLion.from_db('default', ['sealion_ptr_id'], [1])
instance._state.sealed = True
instance.seal()
message = "Cannot fetch related field sealion_ptr on a sealed object."
with self.assertRaisesMessage(SealedObject, message):
instance.sealion_ptr

def test_sealed_instance_m2m_access(self):
instance = SeaLion.from_db('default', ['id'], [1])
instance._state.sealed = True
instance.seal()
message = "Cannot fetch many-to-many field previous_locations on a sealed object."
with self.assertRaisesMessage(SealedObject, message):
instance.previous_locations.all()

def test_sealed_instance_reverse_m2m_access(self):
instance = Location.from_db('default', ['id'], [1])
instance._state.sealed = True
instance.seal()
message = "Cannot fetch many-to-many field previous_visitors on a sealed object."
with self.assertRaisesMessage(SealedObject, message):
instance.previous_visitors.all()