Updates
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
"""
|
||||
Settings for REST framework are all namespaced in the REST_FRAMEWORK setting.
|
||||
For example your project's `settings.py` file might look like this:
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_RENDERER_CLASSES': [
|
||||
'rest_framework.renderers.JSONRenderer',
|
||||
'rest_framework.renderers.TemplateHTMLRenderer',
|
||||
],
|
||||
'DEFAULT_PARSER_CLASSES': [
|
||||
'rest_framework.parsers.JSONParser',
|
||||
'rest_framework.parsers.FormParser',
|
||||
'rest_framework.parsers.MultiPartParser',
|
||||
],
|
||||
}
|
||||
|
||||
This module provides the `api_setting` object, that is used to access
|
||||
REST framework settings, checking for user settings first, then falling
|
||||
back to the defaults.
|
||||
"""
|
||||
from django.conf import settings
|
||||
# Import from `django.core.signals` instead of the official location
|
||||
# `django.test.signals` to avoid importing the test module unnecessarily.
|
||||
from django.core.signals import setting_changed
|
||||
from django.utils.module_loading import import_string
|
||||
|
||||
from rest_framework import ISO_8601
|
||||
|
||||
DEFAULTS = {
|
||||
# Base API policies
|
||||
'DEFAULT_RENDERER_CLASSES': [
|
||||
'rest_framework.renderers.JSONRenderer',
|
||||
'rest_framework.renderers.BrowsableAPIRenderer',
|
||||
],
|
||||
'DEFAULT_PARSER_CLASSES': [
|
||||
'rest_framework.parsers.JSONParser',
|
||||
'rest_framework.parsers.FormParser',
|
||||
'rest_framework.parsers.MultiPartParser'
|
||||
],
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
'rest_framework.authentication.BasicAuthentication'
|
||||
],
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.AllowAny',
|
||||
],
|
||||
'DEFAULT_THROTTLE_CLASSES': [],
|
||||
'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
|
||||
'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
|
||||
'DEFAULT_VERSIONING_CLASS': None,
|
||||
|
||||
# Generic view behavior
|
||||
'DEFAULT_PAGINATION_CLASS': None,
|
||||
'DEFAULT_FILTER_BACKENDS': [],
|
||||
|
||||
# Schema
|
||||
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.openapi.AutoSchema',
|
||||
|
||||
# Throttling
|
||||
'DEFAULT_THROTTLE_RATES': {
|
||||
'user': None,
|
||||
'anon': None,
|
||||
},
|
||||
'NUM_PROXIES': None,
|
||||
|
||||
# Pagination
|
||||
'PAGE_SIZE': None,
|
||||
|
||||
# Filtering
|
||||
'SEARCH_PARAM': 'search',
|
||||
'ORDERING_PARAM': 'ordering',
|
||||
|
||||
# Versioning
|
||||
'DEFAULT_VERSION': None,
|
||||
'ALLOWED_VERSIONS': None,
|
||||
'VERSION_PARAM': 'version',
|
||||
|
||||
# Authentication
|
||||
'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
|
||||
'UNAUTHENTICATED_TOKEN': None,
|
||||
|
||||
# View configuration
|
||||
'VIEW_NAME_FUNCTION': 'rest_framework.views.get_view_name',
|
||||
'VIEW_DESCRIPTION_FUNCTION': 'rest_framework.views.get_view_description',
|
||||
|
||||
# Exception handling
|
||||
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
|
||||
'NON_FIELD_ERRORS_KEY': 'non_field_errors',
|
||||
|
||||
# Testing
|
||||
'TEST_REQUEST_RENDERER_CLASSES': [
|
||||
'rest_framework.renderers.MultiPartRenderer',
|
||||
'rest_framework.renderers.JSONRenderer'
|
||||
],
|
||||
'TEST_REQUEST_DEFAULT_FORMAT': 'multipart',
|
||||
|
||||
# Hyperlink settings
|
||||
'URL_FORMAT_OVERRIDE': 'format',
|
||||
'FORMAT_SUFFIX_KWARG': 'format',
|
||||
'URL_FIELD_NAME': 'url',
|
||||
|
||||
# Input and output formats
|
||||
'DATE_FORMAT': ISO_8601,
|
||||
'DATE_INPUT_FORMATS': [ISO_8601],
|
||||
|
||||
'DATETIME_FORMAT': ISO_8601,
|
||||
'DATETIME_INPUT_FORMATS': [ISO_8601],
|
||||
|
||||
'TIME_FORMAT': ISO_8601,
|
||||
'TIME_INPUT_FORMATS': [ISO_8601],
|
||||
|
||||
# Encoding
|
||||
'UNICODE_JSON': True,
|
||||
'COMPACT_JSON': True,
|
||||
'STRICT_JSON': True,
|
||||
'COERCE_DECIMAL_TO_STRING': True,
|
||||
'UPLOADED_FILES_USE_URL': True,
|
||||
|
||||
# Browsable API
|
||||
'HTML_SELECT_CUTOFF': 1000,
|
||||
'HTML_SELECT_CUTOFF_TEXT': "More than {count} items...",
|
||||
|
||||
# Schemas
|
||||
'SCHEMA_COERCE_PATH_PK': True,
|
||||
'SCHEMA_COERCE_METHOD_NAMES': {
|
||||
'retrieve': 'read',
|
||||
'destroy': 'delete'
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# List of settings that may be in string import notation.
|
||||
IMPORT_STRINGS = [
|
||||
'DEFAULT_RENDERER_CLASSES',
|
||||
'DEFAULT_PARSER_CLASSES',
|
||||
'DEFAULT_AUTHENTICATION_CLASSES',
|
||||
'DEFAULT_PERMISSION_CLASSES',
|
||||
'DEFAULT_THROTTLE_CLASSES',
|
||||
'DEFAULT_CONTENT_NEGOTIATION_CLASS',
|
||||
'DEFAULT_METADATA_CLASS',
|
||||
'DEFAULT_VERSIONING_CLASS',
|
||||
'DEFAULT_PAGINATION_CLASS',
|
||||
'DEFAULT_FILTER_BACKENDS',
|
||||
'DEFAULT_SCHEMA_CLASS',
|
||||
'EXCEPTION_HANDLER',
|
||||
'TEST_REQUEST_RENDERER_CLASSES',
|
||||
'UNAUTHENTICATED_USER',
|
||||
'UNAUTHENTICATED_TOKEN',
|
||||
'VIEW_NAME_FUNCTION',
|
||||
'VIEW_DESCRIPTION_FUNCTION'
|
||||
]
|
||||
|
||||
|
||||
# List of settings that have been removed
|
||||
REMOVED_SETTINGS = [
|
||||
'PAGINATE_BY', 'PAGINATE_BY_PARAM', 'MAX_PAGINATE_BY',
|
||||
]
|
||||
|
||||
|
||||
def perform_import(val, setting_name):
|
||||
"""
|
||||
If the given setting is a string import notation,
|
||||
then perform the necessary import or imports.
|
||||
"""
|
||||
if val is None:
|
||||
return None
|
||||
elif isinstance(val, str):
|
||||
return import_from_string(val, setting_name)
|
||||
elif isinstance(val, (list, tuple)):
|
||||
return [import_from_string(item, setting_name) for item in val]
|
||||
return val
|
||||
|
||||
|
||||
def import_from_string(val, setting_name):
|
||||
"""
|
||||
Attempt to import a class from a string representation.
|
||||
"""
|
||||
try:
|
||||
return import_string(val)
|
||||
except ImportError as e:
|
||||
msg = "Could not import '%s' for API setting '%s'. %s: %s." % (val, setting_name, e.__class__.__name__, e)
|
||||
raise ImportError(msg)
|
||||
|
||||
|
||||
class APISettings:
|
||||
"""
|
||||
A settings object that allows REST Framework settings to be accessed as
|
||||
properties. For example:
|
||||
|
||||
from rest_framework.settings import api_settings
|
||||
print(api_settings.DEFAULT_RENDERER_CLASSES)
|
||||
|
||||
Any setting with string import paths will be automatically resolved
|
||||
and return the class, rather than the string literal.
|
||||
|
||||
Note:
|
||||
This is an internal class that is only compatible with settings namespaced
|
||||
under the REST_FRAMEWORK name. It is not intended to be used by 3rd-party
|
||||
apps, and test helpers like `override_settings` may not work as expected.
|
||||
"""
|
||||
def __init__(self, user_settings=None, defaults=None, import_strings=None):
|
||||
if user_settings:
|
||||
self._user_settings = self.__check_user_settings(user_settings)
|
||||
self.defaults = defaults or DEFAULTS
|
||||
self.import_strings = import_strings or IMPORT_STRINGS
|
||||
self._cached_attrs = set()
|
||||
|
||||
@property
|
||||
def user_settings(self):
|
||||
if not hasattr(self, '_user_settings'):
|
||||
self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
|
||||
return self._user_settings
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if attr not in self.defaults:
|
||||
raise AttributeError("Invalid API setting: '%s'" % attr)
|
||||
|
||||
try:
|
||||
# Check if present in user settings
|
||||
val = self.user_settings[attr]
|
||||
except KeyError:
|
||||
# Fall back to defaults
|
||||
val = self.defaults[attr]
|
||||
|
||||
# Coerce import strings into classes
|
||||
if attr in self.import_strings:
|
||||
val = perform_import(val, attr)
|
||||
|
||||
# Cache the result
|
||||
self._cached_attrs.add(attr)
|
||||
setattr(self, attr, val)
|
||||
return val
|
||||
|
||||
def __check_user_settings(self, user_settings):
|
||||
SETTINGS_DOC = "https://www.django-rest-framework.org/api-guide/settings/"
|
||||
for setting in REMOVED_SETTINGS:
|
||||
if setting in user_settings:
|
||||
raise RuntimeError("The '%s' setting has been removed. Please refer to '%s' for available settings." % (setting, SETTINGS_DOC))
|
||||
return user_settings
|
||||
|
||||
def reload(self):
|
||||
for attr in self._cached_attrs:
|
||||
delattr(self, attr)
|
||||
self._cached_attrs.clear()
|
||||
if hasattr(self, '_user_settings'):
|
||||
delattr(self, '_user_settings')
|
||||
|
||||
|
||||
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)
|
||||
|
||||
|
||||
def reload_api_settings(*args, **kwargs):
|
||||
setting = kwargs['setting']
|
||||
if setting == 'REST_FRAMEWORK':
|
||||
api_settings.reload()
|
||||
|
||||
|
||||
setting_changed.connect(reload_api_settings)
|
||||
Reference in New Issue
Block a user