From 20933e69ebd44783a29bfe0f9efefaacbf3223cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Wr=C3=B3bel?= Date: Sun, 7 May 2017 18:11:56 +0100 Subject: [PATCH] Fix for apps that don't load contenttypes module. PR #319 brought support for generic relations. Unfortunately apps that don't add contenttypes to it's INSTALLED_APPS would crash and burn: ``` RuntimeError: Model class django.contrib.contenttypes.models.ContentType doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS. ``` Also using `type(something) is object()` comparison as a safer alternative to `type(something) is type(None)`. If `something` happened to be `None` we would enter a branch that was never supposed to run. --- CHANGELOG.md | 1 + rest_framework_json_api/utils.py | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47b84425..d6e68e6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ v2.3.0 * When `JSON_API_FORMAT_KEYS` is False (the default) do not translate request attributes and relations to snake\_case format. This conversion was unexpected and there was no way to turn it off. +* Fix for apps that don't use `django.contrib.contenttypes`. v2.2.0 diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py index 26079c0c..a652dec9 100644 --- a/rest_framework_json_api/utils.py +++ b/rest_framework_json_api/utils.py @@ -20,21 +20,28 @@ try: from rest_framework.serializers import ManyRelatedField except ImportError: - ManyRelatedField = type(None) + ManyRelatedField = object() try: from rest_framework_nested.relations import HyperlinkedRouterField except ImportError: - HyperlinkedRouterField = type(None) + HyperlinkedRouterField = object() if django.VERSION >= (1, 9): from django.db.models.fields.related_descriptors import ManyToManyDescriptor, ReverseManyToOneDescriptor - ReverseManyRelatedObjectsDescriptor = type(None) - from django.contrib.contenttypes.fields import ReverseGenericManyToOneDescriptor + ReverseManyRelatedObjectsDescriptor = object() else: from django.db.models.fields.related import ManyRelatedObjectsDescriptor as ManyToManyDescriptor from django.db.models.fields.related import ForeignRelatedObjectsDescriptor as ReverseManyToOneDescriptor from django.db.models.fields.related import ReverseManyRelatedObjectsDescriptor + +# Generic relation descriptor from django.contrib.contenttypes. +if 'django.contrib.contenttypes' not in settings.INSTALLED_APPS: # pragma: no cover + # Target application does not use contenttypes. Importing would cause errors. + ReverseGenericManyToOneDescriptor = object() +elif django.VERSION >= (1, 9): + from django.contrib.contenttypes.fields import ReverseGenericManyToOneDescriptor +else: from django.contrib.contenttypes.fields import ReverseGenericRelatedObjectsDescriptor as ReverseGenericManyToOneDescriptor