settings.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. """
  2. Settings for REST framework are all namespaced in the REST_FRAMEWORK setting.
  3. For example your project's `settings.py` file might look like this:
  4. REST_FRAMEWORK = {
  5. 'DEFAULT_RENDERER_CLASSES': [
  6. 'rest_framework.renderers.JSONRenderer',
  7. 'rest_framework.renderers.TemplateHTMLRenderer',
  8. ],
  9. 'DEFAULT_PARSER_CLASSES': [
  10. 'rest_framework.parsers.JSONParser',
  11. 'rest_framework.parsers.FormParser',
  12. 'rest_framework.parsers.MultiPartParser',
  13. ],
  14. }
  15. This module provides the `api_setting` object, that is used to access
  16. REST framework settings, checking for user settings first, then falling
  17. back to the defaults.
  18. """
  19. from django.conf import settings
  20. from django.test.signals import setting_changed
  21. from django.utils.module_loading import import_string
  22. from rest_framework import ISO_8601
  23. DEFAULTS = {
  24. # Base API policies
  25. 'DEFAULT_RENDERER_CLASSES': [
  26. 'rest_framework.renderers.JSONRenderer',
  27. 'rest_framework.renderers.BrowsableAPIRenderer',
  28. ],
  29. 'DEFAULT_PARSER_CLASSES': [
  30. 'rest_framework.parsers.JSONParser',
  31. 'rest_framework.parsers.FormParser',
  32. 'rest_framework.parsers.MultiPartParser'
  33. ],
  34. 'DEFAULT_AUTHENTICATION_CLASSES': [
  35. 'rest_framework.authentication.SessionAuthentication',
  36. 'rest_framework.authentication.BasicAuthentication'
  37. ],
  38. 'DEFAULT_PERMISSION_CLASSES': [
  39. 'rest_framework.permissions.AllowAny',
  40. ],
  41. 'DEFAULT_THROTTLE_CLASSES': [],
  42. 'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'rest_framework.negotiation.DefaultContentNegotiation',
  43. 'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata',
  44. 'DEFAULT_VERSIONING_CLASS': None,
  45. # Generic view behavior
  46. 'DEFAULT_PAGINATION_CLASS': None,
  47. 'DEFAULT_FILTER_BACKENDS': [],
  48. # Schema
  49. 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.openapi.AutoSchema',
  50. # Throttling
  51. 'DEFAULT_THROTTLE_RATES': {
  52. 'user': None,
  53. 'anon': None,
  54. },
  55. 'NUM_PROXIES': None,
  56. # Pagination
  57. 'PAGE_SIZE': None,
  58. # Filtering
  59. 'SEARCH_PARAM': 'search',
  60. 'ORDERING_PARAM': 'ordering',
  61. # Versioning
  62. 'DEFAULT_VERSION': None,
  63. 'ALLOWED_VERSIONS': None,
  64. 'VERSION_PARAM': 'version',
  65. # Authentication
  66. 'UNAUTHENTICATED_USER': 'django.contrib.auth.models.AnonymousUser',
  67. 'UNAUTHENTICATED_TOKEN': None,
  68. # View configuration
  69. 'VIEW_NAME_FUNCTION': 'rest_framework.views.get_view_name',
  70. 'VIEW_DESCRIPTION_FUNCTION': 'rest_framework.views.get_view_description',
  71. # Exception handling
  72. 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
  73. 'NON_FIELD_ERRORS_KEY': 'non_field_errors',
  74. # Testing
  75. 'TEST_REQUEST_RENDERER_CLASSES': [
  76. 'rest_framework.renderers.MultiPartRenderer',
  77. 'rest_framework.renderers.JSONRenderer'
  78. ],
  79. 'TEST_REQUEST_DEFAULT_FORMAT': 'multipart',
  80. # Hyperlink settings
  81. 'URL_FORMAT_OVERRIDE': 'format',
  82. 'FORMAT_SUFFIX_KWARG': 'format',
  83. 'URL_FIELD_NAME': 'url',
  84. # Input and output formats
  85. 'DATE_FORMAT': ISO_8601,
  86. 'DATE_INPUT_FORMATS': [ISO_8601],
  87. 'DATETIME_FORMAT': ISO_8601,
  88. 'DATETIME_INPUT_FORMATS': [ISO_8601],
  89. 'TIME_FORMAT': ISO_8601,
  90. 'TIME_INPUT_FORMATS': [ISO_8601],
  91. # Encoding
  92. 'UNICODE_JSON': True,
  93. 'COMPACT_JSON': True,
  94. 'STRICT_JSON': True,
  95. 'COERCE_DECIMAL_TO_STRING': True,
  96. 'UPLOADED_FILES_USE_URL': True,
  97. # Browseable API
  98. 'HTML_SELECT_CUTOFF': 1000,
  99. 'HTML_SELECT_CUTOFF_TEXT': "More than {count} items...",
  100. # Schemas
  101. 'SCHEMA_COERCE_PATH_PK': True,
  102. 'SCHEMA_COERCE_METHOD_NAMES': {
  103. 'retrieve': 'read',
  104. 'destroy': 'delete'
  105. },
  106. }
  107. # List of settings that may be in string import notation.
  108. IMPORT_STRINGS = [
  109. 'DEFAULT_RENDERER_CLASSES',
  110. 'DEFAULT_PARSER_CLASSES',
  111. 'DEFAULT_AUTHENTICATION_CLASSES',
  112. 'DEFAULT_PERMISSION_CLASSES',
  113. 'DEFAULT_THROTTLE_CLASSES',
  114. 'DEFAULT_CONTENT_NEGOTIATION_CLASS',
  115. 'DEFAULT_METADATA_CLASS',
  116. 'DEFAULT_VERSIONING_CLASS',
  117. 'DEFAULT_PAGINATION_CLASS',
  118. 'DEFAULT_FILTER_BACKENDS',
  119. 'DEFAULT_SCHEMA_CLASS',
  120. 'EXCEPTION_HANDLER',
  121. 'TEST_REQUEST_RENDERER_CLASSES',
  122. 'UNAUTHENTICATED_USER',
  123. 'UNAUTHENTICATED_TOKEN',
  124. 'VIEW_NAME_FUNCTION',
  125. 'VIEW_DESCRIPTION_FUNCTION'
  126. ]
  127. # List of settings that have been removed
  128. REMOVED_SETTINGS = [
  129. 'PAGINATE_BY', 'PAGINATE_BY_PARAM', 'MAX_PAGINATE_BY',
  130. ]
  131. def perform_import(val, setting_name):
  132. """
  133. If the given setting is a string import notation,
  134. then perform the necessary import or imports.
  135. """
  136. if val is None:
  137. return None
  138. elif isinstance(val, str):
  139. return import_from_string(val, setting_name)
  140. elif isinstance(val, (list, tuple)):
  141. return [import_from_string(item, setting_name) for item in val]
  142. return val
  143. def import_from_string(val, setting_name):
  144. """
  145. Attempt to import a class from a string representation.
  146. """
  147. try:
  148. return import_string(val)
  149. except ImportError as e:
  150. msg = "Could not import '%s' for API setting '%s'. %s: %s." % (val, setting_name, e.__class__.__name__, e)
  151. raise ImportError(msg)
  152. class APISettings:
  153. """
  154. A settings object that allows REST Framework settings to be accessed as
  155. properties. For example:
  156. from rest_framework.settings import api_settings
  157. print(api_settings.DEFAULT_RENDERER_CLASSES)
  158. Any setting with string import paths will be automatically resolved
  159. and return the class, rather than the string literal.
  160. Note:
  161. This is an internal class that is only compatible with settings namespaced
  162. under the REST_FRAMEWORK name. It is not intended to be used by 3rd-party
  163. apps, and test helpers like `override_settings` may not work as expected.
  164. """
  165. def __init__(self, user_settings=None, defaults=None, import_strings=None):
  166. if user_settings:
  167. self._user_settings = self.__check_user_settings(user_settings)
  168. self.defaults = defaults or DEFAULTS
  169. self.import_strings = import_strings or IMPORT_STRINGS
  170. self._cached_attrs = set()
  171. @property
  172. def user_settings(self):
  173. if not hasattr(self, '_user_settings'):
  174. self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
  175. return self._user_settings
  176. def __getattr__(self, attr):
  177. if attr not in self.defaults:
  178. raise AttributeError("Invalid API setting: '%s'" % attr)
  179. try:
  180. # Check if present in user settings
  181. val = self.user_settings[attr]
  182. except KeyError:
  183. # Fall back to defaults
  184. val = self.defaults[attr]
  185. # Coerce import strings into classes
  186. if attr in self.import_strings:
  187. val = perform_import(val, attr)
  188. # Cache the result
  189. self._cached_attrs.add(attr)
  190. setattr(self, attr, val)
  191. return val
  192. def __check_user_settings(self, user_settings):
  193. SETTINGS_DOC = "https://www.django-rest-framework.org/api-guide/settings/"
  194. for setting in REMOVED_SETTINGS:
  195. if setting in user_settings:
  196. raise RuntimeError("The '%s' setting has been removed. Please refer to '%s' for available settings." % (setting, SETTINGS_DOC))
  197. return user_settings
  198. def reload(self):
  199. for attr in self._cached_attrs:
  200. delattr(self, attr)
  201. self._cached_attrs.clear()
  202. if hasattr(self, '_user_settings'):
  203. delattr(self, '_user_settings')
  204. api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)
  205. def reload_api_settings(*args, **kwargs):
  206. setting = kwargs['setting']
  207. if setting == 'REST_FRAMEWORK':
  208. api_settings.reload()
  209. setting_changed.connect(reload_api_settings)