From 74c50b953557ea283a6cd601ad3656379369eb47 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 6 Sep 2012 15:42:54 +0100 Subject: [PATCH] Settings suppport importpaths --- djangorestframework/request.py | 25 ++++++++-- djangorestframework/settings.py | 86 +++++++++++++++++++++++++++------ 2 files changed, 90 insertions(+), 21 deletions(-) diff --git a/djangorestframework/request.py b/djangorestframework/request.py index cddb14157..6c00ff621 100644 --- a/djangorestframework/request.py +++ b/djangorestframework/request.py @@ -11,9 +11,8 @@ The wrapped request then offers a richer API, in particular : """ from StringIO import StringIO -from django.contrib.auth.models import AnonymousUser - from djangorestframework import exceptions +from djangorestframework.settings import api_settings from djangorestframework.utils.mediatypes import is_form_media_type @@ -251,10 +250,26 @@ class Request(object): return self._not_authenticated() def _not_authenticated(self): - return (AnonymousUser(), None) + """ + Return a two-tuple of (user, authtoken), representing an + unauthenticated request. - def __getattr__(self, name): + By default this will be (AnonymousUser, None). + """ + if api_settings.UNAUTHENTICATED_USER: + user = api_settings.UNAUTHENTICATED_USER() + else: + user = None + + if api_settings.UNAUTHENTICATED_TOKEN: + auth = api_settings.UNAUTHENTICATED_TOKEN() + else: + auth = None + + return (user, auth) + + def __getattr__(self, attr): """ Proxy other attributes to the underlying HttpRequest object. """ - return getattr(self._request, name) + return getattr(self._request, attr) diff --git a/djangorestframework/settings.py b/djangorestframework/settings.py index e801a9f1c..f25133d52 100644 --- a/djangorestframework/settings.py +++ b/djangorestframework/settings.py @@ -15,35 +15,89 @@ API_SETTINGS = { """ from django.conf import settings -from djangorestframework import renderers +from django.utils import importlib from djangorestframework.compat import yaml DEFAULTS = { 'DEFAULT_RENDERERS': ( - renderers.JSONRenderer, - renderers.JSONPRenderer, - # renderers.DocumentingHTMLRenderer, - # renderers.DocumentingXHTMLRenderer, - renderers.DocumentingPlainTextRenderer, - # renderers.XMLRenderer - ) + 'djangorestframework.renderers.JSONRenderer', + 'djangorestframework.renderers.JSONPRenderer', + 'djangorestframework.renderers.DocumentingPlainTextRenderer', + ), + 'DEFAULT_PARSERS': ( + 'djangorestframework.parsers.JSONParser', + 'djangorestframework.parsers.FormParser' + ), + 'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser', + 'UNAUTHENTICATED_TOKEN': None } if yaml: - DEFAULTS['DEFAULT_RENDERERS'] += (renderers.YAMLRenderer, ) + DEFAULTS['DEFAULT_RENDERERS'] += ('djangorestframework.renderers.YAMLRenderer', ) + + +# List of settings that may be in string import notation. +IMPORT_STRINGS = ( + 'DEFAULT_RENDERERS', + 'UNAUTHENTICATED_USER', + 'UNAUTHENTICATED_TOKEN' +) + + +def perform_import(val, setting): + """ + If the given setting is a string import notation, + then perform the necessary import or imports. + """ + if val is None or setting not in IMPORT_STRINGS: + return val + + try: + if isinstance(val, basestring): + return import_from_string(val) + elif isinstance(val, (list, tuple)): + return [import_from_string(item) for item in val] + return val + except: + msg = "Could not import '%s' for API setting '%s'" % (val, setting) + raise ImportError(msg) + + +def import_from_string(val): + """ + Attempt to import a class from a string representation. + """ + # Nod to tastypie's use of importlib. + parts = val.split('.') + module_path, class_name = '.'.join(parts[:-1]), parts[-1] + module = importlib.import_module(module_path) + return getattr(module, class_name) class APISettings(object): + """ + A settings object, that allows API settings to be accessed as properties. + For example: + + from djangorestframework.settings import api_settings + print api_settings.DEFAULT_RENDERERS + + Any setting with string import paths will be resolved. + """ def __getattr__(self, attr): + if attr not in DEFAULTS.keys(): + raise AttributeError("Invalid API setting: '%s'" % attr) + try: - return settings.API_SETTINGS[attr] + # Check if present in user settings + val = perform_import(settings.API_SETTINGS[attr], attr) except (AttributeError, KeyError): - # 'API_SETTINGS' does not exist, - # or requested setting is not present in 'API_SETTINGS'. - try: - return DEFAULTS[attr] - except KeyError: - raise AttributeError("No such setting '%s'" % attr) + # Fall back to defaults + val = perform_import(DEFAULTS[attr], attr) + + # Cache the result + setattr(self, attr, val) + return val api_settings = APISettings()