Skip to content

Commit

Permalink
Merge pull request #235 from benkonrath/contrib-guardian
Browse files Browse the repository at this point in the history
Add helper function for django-guardian.
  • Loading branch information
vdboor committed Sep 12, 2016
2 parents 7fec242 + c695029 commit 7cd5f84
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 0 deletions.
9 changes: 9 additions & 0 deletions docs/third-party.rst
Expand Up @@ -97,7 +97,16 @@ This doesn't work, since it needs to look for revisions of the child model. Usin
the view of the actual child model is used, similar to the way the regular change and delete views are redirected.


django-guardian support
-----------------------

You can enable the content type of the base model to be used for the object levels permissions by setting the
django-guardian_ option `GUARDIAN_GET_CONTENT_TYPE` to `polymorphic.contrib.get_polymorphic_base_content_type`. Read
more about this option in the `django-guardian documentation <https://django-guardian.readthedocs.io/en/latest/configuration.html#guardian-get-content-type>`_.


.. _django-reversion: https://github.com/etianen/django-reversion
.. _django-reversion-compare: https://github.com/jedie/django-reversion-compare
.. _django-mptt: https://github.com/django-mptt/django-mptt
.. _django-polymorphic-tree: https://github.com/django-polymorphic/django-polymorphic-tree
.. _django-guardian: https://github.com/django-guardian/django-guardian
Empty file added polymorphic/contrib/__init__.py
Empty file.
35 changes: 35 additions & 0 deletions polymorphic/contrib/guardian.py
@@ -0,0 +1,35 @@
from django.contrib.contenttypes.models import ContentType


def get_polymorphic_base_content_type(obj):
"""
Helper function to return the base polymorphic content type id. This should used with django-guardian and the
GUARDIAN_GET_CONTENT_TYPE option.
See the django-guardian documentation for more information:
https://django-guardian.readthedocs.io/en/latest/configuration.html#guardian-get-content-type
"""
if hasattr(obj, 'polymorphic_model_marker'):
try:
superclasses = list(obj.__class__.mro())
except TypeError:
# obj is an object so mro() need to be called with the obj.
superclasses = list(obj.__class__.mro(obj))

polymorphic_superclasses = list()
for sclass in superclasses:
if hasattr(sclass, 'polymorphic_model_marker'):
polymorphic_superclasses.append(sclass)

# PolymorphicMPTT adds an additional class between polymorphic and base class.
if hasattr(obj, 'can_have_children'):
root_polymorphic_class = polymorphic_superclasses[-3]
else:
root_polymorphic_class = polymorphic_superclasses[-2]
ctype = ContentType.objects.get_for_model(root_polymorphic_class)

else:
ctype = ContentType.objects.get_for_model(obj)

return ctype
21 changes: 21 additions & 0 deletions polymorphic/tests.py
Expand Up @@ -21,6 +21,7 @@
from django.contrib.contenttypes.models import ContentType
from django.utils import six

from polymorphic.contrib.guardian import get_polymorphic_base_content_type
from polymorphic.models import PolymorphicModel
from polymorphic.managers import PolymorphicManager
from polymorphic.query import PolymorphicQuerySet
Expand Down Expand Up @@ -195,6 +196,7 @@ class ModelWithMyManagerNoDefault(ShowFieldTypeAndContent, Model2A):
my_objects = MyManager()
field4 = models.CharField(max_length=10)


class ModelWithMyManagerDefault(ShowFieldTypeAndContent, Model2A):
my_objects = MyManager()
objects = PolymorphicManager()
Expand Down Expand Up @@ -1194,6 +1196,24 @@ def test_polymorphic__expressions(self):
result = Model2B.objects.annotate(val=Concat('field1', 'field2'))
self.assertEqual(list(result), [])

def test_contrib_guardian(self):
# Regular Django inheritance should return the child model content type.
obj = PlainC()
ctype = get_polymorphic_base_content_type(obj)
self.assertEqual(ctype.name, 'plain c')

ctype = get_polymorphic_base_content_type(PlainC)
self.assertEqual(ctype.name, 'plain c')

# Polymorphic inheritance should return the parent model content type.
obj = Model2D()
ctype = get_polymorphic_base_content_type(obj)
self.assertEqual(ctype.name, 'model2a')

ctype = get_polymorphic_base_content_type(Model2D)
self.assertEqual(ctype.name, 'model2a')


class RegressionTests(TestCase):

def test_for_query_result_incomplete_with_inheritance(self):
Expand All @@ -1215,6 +1235,7 @@ def test_for_query_result_incomplete_with_inheritance(self):
expected_queryset = [bottom]
self.assertQuerysetEqual(Bottom.objects.all(), [repr(r) for r in expected_queryset])


class MultipleDatabasesTests(TestCase):
multi_db = True

Expand Down

0 comments on commit 7cd5f84

Please sign in to comment.