Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: encode/django-rest-framework
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3.14.0
Choose a base ref
...
head repository: encode/django-rest-framework
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3.15.2
Choose a head ref

Commits on Sep 22, 2022

  1. Use correct class to indicate present deprecation (#8665)

    `PendingDeprecationWarning` means "we plan to deprecate, but haven't
    yet." A feature that's to be deleted in the next release is not planned
    to be deprecated; it **is** deprecated.
    
    > Base class for warnings about features which are obsolete and expected
    > to be deprecated in the future, but are not deprecated at the moment.
    >
    > This class is rarely used as emitting a warning about a possible
    > upcoming deprecation is unusual, and DeprecationWarning is preferred for
    > already active deprecations.
    
    https://docs.python.org/3/library/exceptions.html#PendingDeprecationWarning
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    DavidCain and tomchristie authored Sep 22, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    2de5081 View commit details

Commits on Sep 26, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    73f4835 View commit details

Commits on Sep 27, 2022

  1. Update documentation on dependency installation (#8566)

    We depend on pytz, but until late last year we got it implicitly through
    depending on Django. Since their release 4.0, however, they no longer
    depend on pytz; commit 250479d added the dependency directly to our
    metadata in setup.py, but the documentation about dependencies (most
    importantly, the instructions for new contributors) was left untouched.
    
    This commit updates the new contributor instructions to suggest an
    "editable installation" of the project at the step that previously had
    users manually install Django. In this mode, pip fetches and installs
    the project dependencies automatically (so in the unlikely event we grow
    another dependency, that doc doesn't need to be changed again) and makes
    the project available to the virtualenv's python as a normal package,
    but doesn't require reinstallation for mundane edits.
    cite-reader authored Sep 27, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    3e51ba4 View commit details
  2. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9e398c5 View commit details

Commits on Oct 3, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    79de112 View commit details
  2. Update requirements-testing.txt (#8680)

    * Update requirements-testing.txt
    
    * Update requirements-testing.txt
    tomchristie authored Oct 3, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    ca75300 View commit details
  3. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    e7777cb View commit details

Commits on Oct 4, 2022

  1. Docs: Updated browsable-api.md (#8678)

    - Replace the broken Bootswatch-Link with an Jsdelivr-Link as suggested at https://bootswatch.com/help/
    - Updated the stated Bootstrap version
    - Added a note that the Bootstrap version must match the default one
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    mschmidm and tomchristie authored Oct 4, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    99cf2c4 View commit details

Commits on Oct 5, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    c10f226 View commit details

Commits on Oct 7, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    d507cd8 View commit details

Commits on Oct 11, 2022

  1. Added examples to schema of CursorPagination (#8687)

    * Added examples to schema of CursorPagination
    
    Fix https://github.com/encode/django-rest-framework/issues/8686
    
    Added missing examples for CursorPagination class to disable warnings in https://github.com/tfranzel/drf-spectacular and make it consistent with other pagination classes.
    
    * Adapted test case for paginated response schema
    norbertschuler authored Oct 11, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    911b207 View commit details
  2. Preserve exception messages for wrapped Django exceptions (#8051)

    * Preserve messages for wrapped Django exceptions
    
    * Fix the test
    
    * Update test_generics.py
    
    * Update test_generics.py
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    vanschelven and tomchristie authored Oct 11, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    56946fa View commit details

Commits on Oct 12, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    20d347a View commit details

Commits on Oct 14, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    1fd268a View commit details
  2. Avoid importing django.test package when not testing (#8699)

    Importing anything `rest_framework` causes `django.test` to be imported.
    This is because DRF registers a receiver on the
    `django.test_signals.setting_changed` signal.
    
    This is not really a problem, but it is good to avoid this because it
    bloats the memory with unnecessary modules (e.g. `django.test`,
    `django.core.servers.basehttp`, `socketserver`) and increases the
    startup time. It also doesn't feel right to import test code into
    non-test code.
    
    Try to import the signal from a core module if possible.
    
    Note that there's another `django.test` import in `MultiPartRenderer`,
    however this import is done lazily only if the functionality is used so
    can be easily avoided.
    bluetech authored Oct 14, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9407833 View commit details

Commits on Oct 17, 2022

  1. Update schemas.md (#8707)

    mka142 authored Oct 17, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    b221aa2 View commit details
  2. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    0cb6937 View commit details
  3. Add a method for getting serializer field name (OpenAPI) (#7493)

    * Add a method for getting serializer field name
    
    * Add docs and test
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    denisorehovsky and tomchristie authored Oct 17, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    35c5be6 View commit details

Commits on Oct 19, 2022

  1. Fixes typo (#8719)

    eltronix authored Oct 19, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    e354331 View commit details
  2. Improve style, fix some typos (#8405)

    * Improve style, fix some typos
    
    * Update docs/api-guide/fields.md
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    franciscouzo and tomchristie authored Oct 19, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    041b88f View commit details

Commits on Oct 20, 2022

  1. Update quickstart.md (#8575)

    * Update quickstart.md
    
    * Use PEP 8 compliant import
    
    * Remove unauthorized password by Django (too common)
    geryogam authored Oct 20, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    2510456 View commit details

Commits on Nov 2, 2022

  1. Update jobs.md (#8737)

    Update remoteok.io to remoteok.com
    Add pyjobs.com
    tompec authored Nov 2, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    1142ee5 View commit details

Commits on Nov 10, 2022

  1. Remove extraneous word "Both" (#8740)

    * Remove extraneous word "Both"
    
    * Update Multiparser docs
    
    Co-authored-by: Lewis Kabui <lewisemm@users.noreply.github.com>
    lewisemm and lewisemm authored Nov 10, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    ae7a2b0 View commit details

Commits on Nov 15, 2022

  1. Fix Pytest's deprecation warnings about nose usage (#8758)

    Pytest 7.2.0 deprecated plain `setup` and `teardown` functions and
    methods as nose idioms:
    https://docs.pytest.org/en/latest/changelog.html#pytest-7-2-0-2022-10-23
    
    `setup` can be safely replaced with `setup_method`:
    https://docs.pytest.org/en/stable/deprecations.html#setup-teardown
    
    Fixes: https://github.com/encode/django-rest-framework/issues/8757
    Signed-off-by: Stanislav Levin <slev@altlinux.org>
    
    Signed-off-by: Stanislav Levin <slev@altlinux.org>
    stanislavlevin authored Nov 15, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    78cdae6 View commit details

Commits on Nov 16, 2022

  1. Possibility to remove trailing zeros on DecimalFields representation (#…

    …6514)
    
    * Added normalize parameter to DecimalField to be able to strip trailing zeros. Fixes #6151.
    
    * Updated docs to include normalize option on DecimalField
    
    * Fixed linting error in test_fields
    
    * Removed comment and renamed normalize to normalize_output as suggested in code review
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    Krolken and tomchristie authored Nov 16, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    d5f228d View commit details

Commits on Nov 17, 2022

  1. Make request consistently available in pagination classes (#8764)

    * Store request in CursorPagination field
    
    * Define request at start of pagination entrypoint
    c-w authored Nov 17, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    759fc6f View commit details
  2. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    3e05237 View commit details
  3. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    df60510 View commit details

Commits on Nov 18, 2022

  1. pytest versions update (#8745)

    * pytest versions update
    
    * pytest>=7.0.0,<8.0
    
    * pytest>=7.2.0,<8.0
    
    * pytest>=6.2.0,<8.0
    auvipy authored Nov 18, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    21fdf06 View commit details
  2. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    cac89ae View commit details

Commits on Nov 21, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    2a2b092 View commit details
  2. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    751808c View commit details
  3. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    dc300aa View commit details

Commits on Nov 22, 2022

  1. FloatField will crash if the input is a number that is too big (#8725)

    * FloatField will crash if the input is a number that is too big
    
    * Added Unit test for float field overflow error catch
    
    * Removed random import
    
    * Removed additional imported ValidationError
    
    * Update rest_framework/fields.py
    
    * Update tests/test_fields.py
    
    Co-authored-by: Asif Saif Uddin <auvipy@gmail.com>
    winmorre and auvipy authored Nov 22, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9e56f54 View commit details
  2. Fixes instance check in ListSerializer.to_representation (#8726) (#8727)

    * Fixes 'RelatedManager' object is not iterable in ListSerializer.to_representation.(#8726)
    
    * Change to only BaseManager
    
    * Commit unit test
    
    * Update tests/test_serializer_lists.py
    
    * Update tests/test_serializer_lists.py
    
    * Update tests/test_serializer_lists.py
    
    * Update tests/test_serializer_lists.py
    
    * Update tests/test_serializer_lists.py
    
    * Update tests/test_serializer_lists.py
    
    * Format import
    
    * Format import
    
    Co-authored-by: Asif Saif Uddin <auvipy@gmail.com>
    954-Ivory and auvipy authored Nov 22, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    03c2ef1 View commit details
  3. fix 404 when page query parameter is empty string (#8578)

    * fix 404 when page query parameter is empty string
    
    * Update pagination.py
    
    * Update pagination.py
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    shipengtaov and tomchristie authored Nov 22, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    0ae3323 View commit details
  4. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    8175f05 View commit details
  5. Update 6-viewsets-and-routers.md (#8590)

    * Update 6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    * Update docs/tutorial/6-viewsets-and-routers.md
    
    Co-authored-by: Asif Saif Uddin <auvipy@gmail.com>
    geryogam and auvipy authored Nov 22, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    fd7d3a7 View commit details
  6. Update schema generation doc & add deprecation notice #8453 (#8773)

    * Update schema generation doc & add deprecation notice #8453
    
    * Update docs/topics/documenting-your-api.md
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    
    * Update docs/topics/documenting-your-api.md
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    
    * Update docs/topics/documenting-your-api.md
    
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    
    Co-authored-by: T. Franzel <13507857+tfranzel@users.noreply.github.com>
    Co-authored-by: Asif Saif Uddin <auvipy@gmail.com>
    Co-authored-by: Tom Christie <tom@tomchristie.com>
    4 people authored Nov 22, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    b87699c View commit details
  7. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    c0d95cb View commit details

Commits on Nov 23, 2022

  1. Represent SafeString as plain string on schema rendering. (#8429)

    * Use SafeString.represent_str to represent SafeString as str
    
    * Add SafeString yaml rendering test
    hashlash authored Nov 23, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    ebde56b View commit details

Commits on Nov 24, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9e328a9 View commit details
  2. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    52f4139 View commit details

Commits on Nov 27, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    4ef0fc1 View commit details
  2. Register Django urls (#8778)

    Without adding the URLs manually, the users and groups APIs were not usable.
    
    My env:
    (venv) ➜  tutorial pip freeze
    asgiref==3.5.2
    astroid==2.12.13
    autopep8==2.0.0
    dill==0.3.6
    Django==4.1.3
    djangorestframework==3.14.0
    isort==5.10.1
    lazy-object-proxy==1.8.0
    mccabe==0.7.0
    platformdirs==2.5.4
    pycodestyle==2.10.0
    pylint==2.15.6
    pylint-django==2.5.3
    pylint-plugin-utils==0.7
    pytz==2022.6
    sqlparse==0.4.3
    tomli==2.0.1
    tomlkit==0.11.6
    wrapt==1.14.1
    tomirgang authored Nov 27, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    3bf6117 View commit details

Commits on Nov 28, 2022

  1. Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    5435b2c View commit details
  2. Remove Core API mentions from docs (#8780)

    * remove coreapi generator mentions & hidden docs
    
    * remove coreapi doc & redirect broken links to github snapshot
    tfranzel authored Nov 28, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    f0095b4 View commit details

Commits on Nov 29, 2022

  1. Avoid inline script execution for injecting CSRF token (#7016)

    Scripts with type="application/json" or "text/plain" are not executed, so we can
    use them to inject dynamic CSRF data, without allowing inline-script execution
    in Content-Security-Policy.
    lukaw3d authored Nov 29, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    6ec6dde View commit details
  2. Make browsable API compatbile with strong CSP (#8784)

    Co-authored-by: Alexander Bliskovsky <abliskovsky@fusionbox.com>
    juspence and Alexander Bliskovsky authored Nov 29, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    1ae812e View commit details

Commits on Dec 1, 2022

  1. Fix bug in validators documentation (#8779)

    Function validators seem to have to return their value (which will become part of `validated_data`) as part of their signature.
    FlorisHoogenboom authored Dec 1, 2022

    Verified

    This commit was created on github.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    614bd87 View commit details
Showing with 4,122 additions and 3,862 deletions.
  1. +8 −1 .github/ISSUE_TEMPLATE/1-issue.md
  2. +13 −0 .github/dependabot.yml
  3. +30 −9 .github/workflows/main.yml
  4. +5 −7 .github/workflows/pre-commit.yml
  5. +16 −3 .pre-commit-config.yaml
  6. +1 −1 CONTRIBUTING.md
  7. +1 −1 PULL_REQUEST_TEMPLATE.md
  8. +7 −10 README.md
  9. +10 −10 docs/api-guide/authentication.md
  10. +31 −8 docs/api-guide/caching.md
  11. +1 −1 docs/api-guide/content-negotiation.md
  12. +3 −4 docs/api-guide/exceptions.md
  13. +69 −62 docs/api-guide/fields.md
  14. +13 −18 docs/api-guide/filtering.md
  15. +2 −2 docs/api-guide/format-suffixes.md
  16. +1 −1 docs/api-guide/generic-views.md
  17. +3 −12 docs/api-guide/pagination.md
  18. +3 −3 docs/api-guide/parsers.md
  19. +9 −4 docs/api-guide/permissions.md
  20. +5 −5 docs/api-guide/relations.md
  21. +5 −5 docs/api-guide/renderers.md
  22. +1 −1 docs/api-guide/requests.md
  23. +11 −11 docs/api-guide/reverse.md
  24. +14 −1 docs/api-guide/routers.md
  25. +39 −13 docs/api-guide/schemas.md
  26. +20 −22 docs/api-guide/serializers.md
  27. +6 −0 docs/api-guide/settings.md
  28. +4 −0 docs/api-guide/status-codes.md
  29. +2 −2 docs/api-guide/throttling.md
  30. +17 −12 docs/api-guide/validators.md
  31. +1 −1 docs/api-guide/views.md
  32. +23 −15 docs/api-guide/viewsets.md
  33. +2 −2 docs/community/3.0-announcement.md
  34. +8 −7 docs/community/3.10-announcement.md
  35. +6 −5 docs/community/3.11-announcement.md
  36. +22 −10 docs/community/3.12-announcement.md
  37. +12 −2 docs/community/3.14-announcement.md
  38. +50 −0 docs/community/3.15-announcement.md
  39. +1 −1 docs/community/3.2-announcement.md
  40. +1 −1 docs/community/3.3-announcement.md
  41. +2 −2 docs/community/3.4-announcement.md
  42. +2 −6 docs/community/3.5-announcement.md
  43. +2 −2 docs/community/3.6-announcement.md
  44. +1 −1 docs/community/3.8-announcement.md
  45. +4 −7 docs/community/3.9-announcement.md
  46. +7 −10 docs/community/contributing.md
  47. +398 −398 docs/community/funding.md
  48. +4 −2 docs/community/jobs.md
  49. +10 −55 docs/community/project-management.md
  50. +115 −8 docs/community/release-notes.md
  51. +14 −3 docs/community/third-party-packages.md
  52. +5 −0 docs/community/tutorials-and-resources.md
  53. +0 −242 docs/coreapi/7-schemas-and-client-libraries.md
  54. +0 −182 docs/coreapi/from-documenting-your-api.md
  55. +0 −29 docs/coreapi/index.md
  56. +0 −854 docs/coreapi/schemas.md
  57. BIN docs/img/premium/svix-premium.png
  58. BIN docs/img/rfm.png
  59. BIN docs/img/rfr.png
  60. +9 −9 docs/index.md
  61. +2 −2 docs/topics/ajax-csrf-cors.md
  62. +0 −527 docs/topics/api-clients.md
  63. +40 −3 docs/topics/browsable-api.md
  64. +49 −41 docs/topics/documenting-your-api.md
  65. +220 −220 docs/topics/html-and-forms.md
  66. +1 −1 docs/topics/rest-hypermedia-hateoas.md
  67. +38 −31 docs/tutorial/1-serialization.md
  68. +1 −1 docs/tutorial/2-requests-and-responses.md
  69. +2 −2 docs/tutorial/3-class-based-views.md
  70. +18 −13 docs/tutorial/6-viewsets-and-routers.md
  71. +30 −27 docs/tutorial/quickstart.md
  72. +14 −0 docs_theme/css/default.css
  73. +2 −1 mkdocs.yml
  74. +3 −2 requirements.txt
  75. +4 −2 requirements/requirements-documentation.txt
  76. +5 −4 requirements/requirements-optionals.txt
  77. +3 −3 requirements/requirements-packaging.txt
  78. +6 −3 requirements/requirements-testing.txt
  79. +5 −7 rest_framework/__init__.py
  80. +3 −3 rest_framework/authentication.py
  81. +0 −4 rest_framework/authtoken/__init__.py
  82. +3 −0 rest_framework/authtoken/admin.py
  83. +17 −0 rest_framework/authtoken/migrations/0004_alter_tokenproxy_options.py
  84. +2 −1 rest_framework/authtoken/models.py
  85. +18 −29 rest_framework/compat.py
  86. +1 −1 rest_framework/decorators.py
  87. +103 −71 rest_framework/fields.py
  88. +70 −24 rest_framework/filters.py
  89. +4 −0 rest_framework/generics.py
  90. +16 −14 rest_framework/metadata.py
  91. +63 −53 rest_framework/pagination.py
  92. +6 −9 rest_framework/parsers.py
  93. +15 −4 rest_framework/permissions.py
  94. +12 −13 rest_framework/relations.py
  95. +17 −11 rest_framework/renderers.py
  96. +7 −2 rest_framework/request.py
  97. +4 −0 rest_framework/response.py
  98. +54 −12 rest_framework/routers.py
  99. +17 −7 rest_framework/schemas/coreapi.py
  100. +2 −2 rest_framework/schemas/generators.py
  101. +1 −1 rest_framework/schemas/inspectors.py
  102. +21 −12 rest_framework/schemas/openapi.py
  103. +113 −78 rest_framework/serializers.py
  104. +4 −2 rest_framework/settings.py
  105. +4 −0 rest_framework/static/rest_framework/css/bootstrap-tweaks.css
  106. +6 −0 rest_framework/static/rest_framework/js/ajax-form.js
  107. +1 −0 rest_framework/static/rest_framework/js/csrf.js
  108. +0 −2 rest_framework/static/rest_framework/js/jquery-3.5.1.min.js
  109. +2 −0 rest_framework/static/rest_framework/js/jquery-3.7.1.min.js
  110. +3 −0 rest_framework/static/rest_framework/js/load-ajax-form.js
  111. +8 −12 rest_framework/templates/rest_framework/admin.html
  112. +11 −15 rest_framework/templates/rest_framework/base.html
  113. +2 −2 rest_framework/templates/rest_framework/docs/error.html
  114. +1 −1 rest_framework/templates/rest_framework/docs/index.html
  115. +1 −1 rest_framework/templates/rest_framework/horizontal/select_multiple.html
  116. +1 −1 rest_framework/templates/rest_framework/pagination/numbers.html
  117. +14 −10 rest_framework/templatetags/rest_framework.py
  118. +2 −15 rest_framework/test.py
  119. +14 −3 rest_framework/utils/encoders.py
  120. +24 −5 rest_framework/utils/field_mapping.py
  121. +1 −1 rest_framework/utils/mediatypes.py
  122. +9 −14 rest_framework/utils/model_meta.py
  123. +2 −2 rest_framework/utils/representation.py
  124. +4 −6 rest_framework/utils/serializer_helpers.py
  125. +25 −0 rest_framework/utils/timezone.py
  126. +50 −4 rest_framework/validators.py
  127. +4 −2 rest_framework/versioning.py
  128. +3 −3 rest_framework/views.py
  129. +1 −2 rest_framework/viewsets.py
  130. +13 −0 runtests.py
  131. +7 −0 setup.cfg
  132. +9 −11 setup.py
  133. +20 −13 tests/authentication/test_authentication.py
  134. +6 −0 tests/browsable_api/test_browsable_api.py
  135. +2 −17 tests/conftest.py
  136. +26 −0 tests/models.py
  137. +53 −2 tests/schemas/test_coreapi.py
  138. +4 −1 tests/schemas/test_managementcommand.py
  139. +128 −1 tests/schemas/test_openapi.py
  140. +5 −0 tests/schemas/views.py
  141. +16 −0 tests/test_decorators.py
  142. +155 −155 tests/test_description.py
  143. +305 −29 tests/test_fields.py
  144. +90 −4 tests/test_filters.py
  145. +32 −1 tests/test_generics.py
  146. +7 −0 tests/test_metadata.py
  147. +49 −53 tests/test_model_serializer.py
  148. +34 −8 tests/test_pagination.py
  149. +26 −0 tests/test_permissions.py
  150. +137 −1 tests/test_relations.py
  151. +63 −5 tests/test_renderers.py
  152. +18 −0 tests/test_request.py
  153. +13 −1 tests/test_response.py
  154. +2 −1 tests/test_reverse.py
  155. +230 −2 tests/test_routers.py
  156. +28 −7 tests/test_serializer.py
  157. +105 −7 tests/test_serializer_lists.py
  158. +7 −7 tests/test_serializer_nested.py
  159. +25 −0 tests/test_settings.py
  160. +20 −20 tests/test_status.py
  161. +2 −2 tests/test_templates.py
  162. +5 −17 tests/test_testing.py
  163. +1 −1 tests/test_throttling.py
  164. +7 −0 tests/test_utils.py
  165. +163 −27 tests/test_validators.py
  166. +14 −4 tests/test_versioning.py
  167. +16 −17 tests/test_viewsets.py
  168. +4 −1 tests/utils.py
  169. +17 −20 tox.ini
9 changes: 8 additions & 1 deletion .github/ISSUE_TEMPLATE/1-issue.md
Original file line number Diff line number Diff line change
@@ -5,6 +5,13 @@ about: Please only raise an issue if you've been advised to do so after discussi

## Checklist

<!--
Note: REST framework is considered feature-complete. New functionality should be implemented outside the core REST framework. For details, please check the docs: https://www.django-rest-framework.org/community/third-party-packages/#about-third-party-packages
-->

- [ ] Raised initially as discussion #...
- [ ] This cannot be dealt with as a third party library. (We prefer new functionality to be [in the form of third party libraries](https://www.django-rest-framework.org/community/third-party-packages/#about-third-party-packages) where possible.)
- [ ] This is not a feature request suitable for implementation outside this project. Please elaborate what it is:
- [ ] compatibility fix for new Django/Python version ...
- [ ] other type of bug fix
- [ ] other type of improvement that does not touch existing code or change existing behavior (e.g. wrapper for new Django field)
- [ ] I have reduced the issue to the simplest possible case.
13 changes: 13 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Keep GitHub Actions up to date with GitHub's Dependabot...
# https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem
version: 2
updates:
- package-ecosystem: github-actions
directory: /
groups:
github-actions:
patterns:
- "*" # Group all Action updates into a single larger pull request
schedule:
interval: weekly
39 changes: 30 additions & 9 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -14,16 +14,16 @@ jobs:
strategy:
matrix:
python-version:
- '3.6'
- '3.7'
- '3.8'
- '3.9'
- '3.10'
- '3.11'
- '3.12'

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: actions/setup-python@v3
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'pip'
@@ -33,19 +33,40 @@ jobs:
run: python -m pip install --upgrade pip setuptools virtualenv wheel

- name: Install dependencies
run: python -m pip install --upgrade codecov tox tox-py
run: python -m pip install --upgrade codecov tox

- name: Run tox targets for ${{ matrix.python-version }}
run: tox --py current
run: tox run -f py$(echo ${{ matrix.python-version }} | tr -d .)

- name: Run extra tox targets
if: ${{ matrix.python-version == '3.9' }}
run: |
python setup.py bdist_wheel
rm -r djangorestframework.egg-info # see #6139
tox -e base,dist,docs
tox -e dist --installpkg ./dist/djangorestframework-*.whl
- name: Upload coverage
run: |
codecov -e TOXENV,DJANGO
test-docs:
name: Test documentation links
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: '3.9'

- name: Install dependencies
run: pip install -r requirements/requirements-documentation.txt

# Start mkdocs server and wait for it to be ready
- run: mkdocs serve &
- run: WAIT_TIME=0 && until nc -vzw 2 localhost 8000 || [ $WAIT_TIME -eq 5 ]; do sleep $(( WAIT_TIME++ )); done
- run: if [ $WAIT_TIME == 5 ]; then echo cannot start mkdocs server on http://localhost:8000; exit 1; fi

- name: Check links
continue-on-error: true
run: pylinkvalidate.py -P http://localhost:8000/

- run: echo "Done"
12 changes: 5 additions & 7 deletions .github/workflows/pre-commit.yml
Original file line number Diff line number Diff line change
@@ -8,17 +8,15 @@ on:

jobs:
pre-commit:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: actions/setup-python@v2
- uses: actions/setup-python@v5
with:
python-version: 3.9
python-version: "3.10"

- uses: pre-commit/action@v2.0.0
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: pre-commit/action@v3.0.1
19 changes: 16 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.4.0
rev: v4.5.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
@@ -9,12 +9,25 @@ repos:
- id: check-symlinks
- id: check-toml
- repo: https://github.com/pycqa/isort
rev: 5.8.0
rev: 5.13.2
hooks:
- id: isort
- repo: https://github.com/PyCQA/flake8
rev: 3.9.0
rev: 7.0.0
hooks:
- id: flake8
additional_dependencies:
- flake8-tidy-imports
- repo: https://github.com/adamchainz/blacken-docs
rev: 1.16.0
hooks:
- id: blacken-docs
exclude: ^(?!docs).*$
additional_dependencies:
- black==23.1.0
- repo: https://github.com/codespell-project/codespell
# Configuration for codespell is in .codespellrc
rev: v2.2.6
hooks:
- id: codespell
exclude: locale|kickstarter-announcement.md|coreapi-0.1.1.js
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Contributing to REST framework

At this point in it's lifespan we consider Django REST framework to be essentially feature-complete. We may accept pull requests that track the continued development of Django versions, but would prefer not to accept new features or code formatting changes.
At this point in its lifespan we consider Django REST framework to be essentially feature-complete. We may accept pull requests that track the continued development of Django versions, but would prefer not to accept new features or code formatting changes.

Apart from minor documentation changes, the [GitHub discussions page](https://github.com/encode/django-rest-framework/discussions) should generally be your starting point. Please only raise an issue or pull request if you've been recommended to do so after discussion.

2 changes: 1 addition & 1 deletion PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*Note*: Before submitting this pull request, please review our [contributing guidelines](https://www.django-rest-framework.org/community/contributing/#pull-requests).
*Note*: Before submitting a code change, please review our [contributing guidelines](https://www.django-rest-framework.org/community/contributing/#pull-requests).

## Description

17 changes: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -27,8 +27,9 @@ The initial aim is to provide a single full-time position on REST framework.
[![][posthog-img]][posthog-url]
[![][cryptapi-img]][cryptapi-url]
[![][fezto-img]][fezto-url]
[![][svix-img]][svix-url]

Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry][sentry-url], [Stream][stream-url], [Spacinov][spacinov-url], [Retool][retool-url], [bit.io][bitio-url], [PostHog][posthog-url], [CryptAPI][cryptapi-url], and [FEZTO][fezto-url].
Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry][sentry-url], [Stream][stream-url], [Spacinov][spacinov-url], [Retool][retool-url], [bit.io][bitio-url], [PostHog][posthog-url], [CryptAPI][cryptapi-url], [FEZTO][fezto-url], and [Svix][svix-url].

---

@@ -38,14 +39,12 @@ Django REST framework is a powerful and flexible toolkit for building Web APIs.

Some reasons you might want to use REST framework:

* The [Web browsable API][sandbox] is a huge usability win for your developers.
* The Web browsable API is a huge usability win for your developers.
* [Authentication policies][authentication] including optional packages for [OAuth1a][oauth1-section] and [OAuth2][oauth2-section].
* [Serialization][serializers] that supports both [ORM][modelserializer-section] and [non-ORM][serializer-section] data sources.
* Customizable all the way down - just use [regular function-based views][functionview-section] if you don't need the [more][generic-views] [powerful][viewsets] [features][routers].
* [Extensive documentation][docs], and [great community support][group].

There is a live example API for testing purposes, [available here][sandbox].

**Below**: *Screenshot from the browsable API*

![Screenshot][image]
@@ -54,8 +53,8 @@ There is a live example API for testing purposes, [available here][sandbox].

# Requirements

* Python 3.6+
* Django 4.1, 4.0, 3.2, 3.1, 3.0
* Python 3.8+
* Django 5.0, 4.2

We **highly recommend** and only officially support the latest patch release of
each Python and Django series.
@@ -173,8 +172,6 @@ Full documentation for the project is available at [https://www.django-rest-fram

For questions and support, use the [REST framework discussion group][group], or `#restframework` on libera.chat IRC.

You may also want to [follow the author on Twitter][twitter].

# Security

Please see the [security policy][security-policy].
@@ -185,9 +182,7 @@ Please see the [security policy][security-policy].
[codecov]: https://codecov.io/github/encode/django-rest-framework?branch=master
[pypi-version]: https://img.shields.io/pypi/v/djangorestframework.svg
[pypi]: https://pypi.org/project/djangorestframework/
[twitter]: https://twitter.com/starletdreaming
[group]: https://groups.google.com/forum/?fromgroups#!forum/django-rest-framework
[sandbox]: https://restframework.herokuapp.com/

[funding]: https://fund.django-rest-framework.org/topics/funding/
[sponsors]: https://fund.django-rest-framework.org/topics/funding/#our-sponsors
@@ -200,6 +195,7 @@ Please see the [security policy][security-policy].
[posthog-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/posthog-readme.png
[cryptapi-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/cryptapi-readme.png
[fezto-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/fezto-readme.png
[svix-img]: https://raw.githubusercontent.com/encode/django-rest-framework/master/docs/img/premium/svix-premium.png

[sentry-url]: https://getsentry.com/welcome/
[stream-url]: https://getstream.io/?utm_source=DjangoRESTFramework&utm_medium=Webpage_Logo_Ad&utm_content=Developer&utm_campaign=DjangoRESTFramework_Jan2022_HomePage
@@ -209,6 +205,7 @@ Please see the [security policy][security-policy].
[posthog-url]: https://posthog.com?utm_source=drf&utm_medium=sponsorship&utm_campaign=open-source-sponsorship
[cryptapi-url]: https://cryptapi.io
[fezto-url]: https://www.fezto.xyz/?utm_source=DjangoRESTFramework
[svix-url]: https://www.svix.com/?utm_source=django-REST&utm_medium=sponsorship

[oauth1-section]: https://www.django-rest-framework.org/api-guide/authentication/#django-rest-framework-oauth
[oauth2-section]: https://www.django-rest-framework.org/api-guide/authentication/#django-oauth-toolkit
20 changes: 10 additions & 10 deletions docs/api-guide/authentication.md
Original file line number Diff line number Diff line change
@@ -201,7 +201,7 @@ If you've already created some users, you can generate tokens for all existing u

#### By exposing an api endpoint

When using `TokenAuthentication`, you may want to provide a mechanism for clients to obtain a token given the username and password. REST framework provides a built-in view to provide this behaviour. To use it, add the `obtain_auth_token` view to your URLconf:
When using `TokenAuthentication`, you may want to provide a mechanism for clients to obtain a token given the username and password. REST framework provides a built-in view to provide this behavior. To use it, add the `obtain_auth_token` view to your URLconf:

from rest_framework.authtoken import views
urlpatterns += [
@@ -216,7 +216,7 @@ The `obtain_auth_token` view will return a JSON response when valid `username` a

Note that the default `obtain_auth_token` view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings.

By default, there are no permissions or throttling applied to the `obtain_auth_token` view. If you do wish to apply to throttle you'll need to override the view class,
By default, there are no permissions or throttling applied to the `obtain_auth_token` view. If you do wish to apply throttling you'll need to override the view class,
and include them using the `throttle_classes` attribute.

If you need a customized version of the `obtain_auth_token` view, you can do so by subclassing the `ObtainAuthToken` view class, and using that in your url conf instead.
@@ -250,7 +250,7 @@ And in your `urls.py`:

#### With Django admin

It is also possible to create Tokens manually through the admin interface. In case you are using a large user base, we recommend that you monkey patch the `TokenAdmin` class customize it to your needs, more specifically by declaring the `user` field as `raw_field`.
It is also possible to create Tokens manually through the admin interface. In case you are using a large user base, we recommend that you monkey patch the `TokenAdmin` class to customize it to your needs, more specifically by declaring the `user` field as `raw_field`.

`your_app/admin.py`:

@@ -289,7 +289,7 @@ If you're using an AJAX-style API with SessionAuthentication, you'll need to mak

**Warning**: Always use Django's standard login view when creating login pages. This will ensure your login views are properly protected.

CSRF validation in REST framework works slightly differently from standard Django due to the need to support both session and non-session based authentication to the same views. This means that only authenticated requests require CSRF tokens, and anonymous requests may be sent without CSRF tokens. This behaviour is not suitable for login views, which should always have CSRF validation applied.
CSRF validation in REST framework works slightly differently from standard Django due to the need to support both session and non-session based authentication to the same views. This means that only authenticated requests require CSRF tokens, and anonymous requests may be sent without CSRF tokens. This behavior is not suitable for login views, which should always have CSRF validation applied.


## RemoteUserAuthentication
@@ -299,15 +299,15 @@ environment variable.

To use it, you must have `django.contrib.auth.backends.RemoteUserBackend` (or a subclass) in your
`AUTHENTICATION_BACKENDS` setting. By default, `RemoteUserBackend` creates `User` objects for usernames that don't
already exist. To change this and other behaviour, consult the
already exist. To change this and other behavior, consult the
[Django documentation](https://docs.djangoproject.com/en/stable/howto/auth-remote-user/).

If successfully authenticated, `RemoteUserAuthentication` provides the following credentials:

* `request.user` will be a Django `User` instance.
* `request.auth` will be `None`.

Consult your web server's documentation for information about configuring an authentication method, e.g.:
Consult your web server's documentation for information about configuring an authentication method, for example:

* [Apache Authentication How-To](https://httpd.apache.org/docs/2.4/howto/auth.html)
* [NGINX (Restricting Access)](https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-http-basic-authentication/)
@@ -338,7 +338,7 @@ If the `.authenticate_header()` method is not overridden, the authentication sch

The following example will authenticate any incoming request as the user given by the username in a custom request header named 'X-USERNAME'.

from django.contrib.auth.models import User
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions

@@ -414,11 +414,11 @@ The [HawkREST][hawkrest] library builds on the [Mohawk][mohawk] library to let y

## HTTP Signature Authentication

HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a way to achieve origin authentication and message integrity for HTTP messages. Similar to [Amazon's HTTP Signature scheme][amazon-http-signature], used by many of its services, it permits stateless, per-request authentication. [Elvio Toccalino][etoccalino] maintains the [djangorestframework-httpsignature][djangorestframework-httpsignature] (outdated) package which provides an easy to use HTTP Signature Authentication mechanism. You can use the updated fork version of [djangorestframework-httpsignature][djangorestframework-httpsignature], which is [drf-httpsig][drf-httpsig].
HTTP Signature (currently a [IETF draft][http-signature-ietf-draft]) provides a way to achieve origin authentication and message integrity for HTTP messages. Similar to [Amazon's HTTP Signature scheme][amazon-http-signature], used by many of its services, it permits stateless, per-request authentication. [Elvio Toccalino][etoccalino] maintains the [djangorestframework-httpsignature][djangorestframework-httpsignature] (outdated) package which provides an easy-to-use HTTP Signature Authentication mechanism. You can use the updated fork version of [djangorestframework-httpsignature][djangorestframework-httpsignature], which is [drf-httpsig][drf-httpsig].

## Djoser

[Djoser][djoser] library provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation. The package works with a custom user model and uses token-based authentication. This is ready to use REST implementation of the Django authentication system.
[Djoser][djoser] library provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation. The package works with a custom user model and uses token-based authentication. This is a ready to use REST implementation of the Django authentication system.

## django-rest-auth / dj-rest-auth

@@ -454,7 +454,7 @@ More information can be found in the [Documentation](https://django-rest-durin.r
[basicauth]: https://tools.ietf.org/html/rfc2617
[permission]: permissions.md
[throttling]: throttling.md
[csrf-ajax]: https://docs.djangoproject.com/en/stable/ref/csrf/#ajax
[csrf-ajax]: https://docs.djangoproject.com/en/stable/howto/csrf/#using-csrf-protection-with-ajax
[mod_wsgi_official]: https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIPassAuthorization.html
[django-oauth-toolkit-getting-started]: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_started.html
[django-rest-framework-oauth]: https://jpadilla.github.io/django-rest-framework-oauth/
39 changes: 31 additions & 8 deletions docs/api-guide/caching.md
Original file line number Diff line number Diff line change
@@ -28,37 +28,60 @@ from rest_framework import viewsets

class UserViewSet(viewsets.ViewSet):
# With cookie: cache requested url for each user for 2 hours
@method_decorator(cache_page(60*60*2))
@method_decorator(cache_page(60 * 60 * 2))
@method_decorator(vary_on_cookie)
def list(self, request, format=None):
content = {
'user_feed': request.user.get_user_feed()
"user_feed": request.user.get_user_feed(),
}
return Response(content)


class ProfileView(APIView):
# With auth: cache requested url for each user for 2 hours
@method_decorator(cache_page(60*60*2))
@method_decorator(vary_on_headers("Authorization",))
@method_decorator(cache_page(60 * 60 * 2))
@method_decorator(vary_on_headers("Authorization"))
def get(self, request, format=None):
content = {
'user_feed': request.user.get_user_feed()
"user_feed": request.user.get_user_feed(),
}
return Response(content)


class PostView(APIView):
# Cache page for the requested url
@method_decorator(cache_page(60*60*2))
@method_decorator(cache_page(60 * 60 * 2))
def get(self, request, format=None):
content = {
'title': 'Post title',
'body': 'Post content'
"title": "Post title",
"body": "Post content",
}
return Response(content)
```


## Using cache with @api_view decorator

When using @api_view decorator, the Django-provided method-based cache decorators such as [`cache_page`][page],
[`vary_on_cookie`][cookie] and [`vary_on_headers`][headers] can be called directly.

```python
from django.views.decorators.cache import cache_page
from django.views.decorators.vary import vary_on_cookie

from rest_framework.decorators import api_view
from rest_framework.response import Response


@cache_page(60 * 15)
@vary_on_cookie
@api_view(["GET"])
def get_user_list(request):
content = {"user_feed": request.user.get_user_feed()}
return Response(content)
```


**NOTE:** The [`cache_page`][page] decorator only caches the
`GET` and `HEAD` responses with status 200.

2 changes: 1 addition & 1 deletion docs/api-guide/content-negotiation.md
Original file line number Diff line number Diff line change
@@ -82,7 +82,7 @@ The default content negotiation class may be set globally, using the `DEFAULT_CO

You can also set the content negotiation used for an individual view, or viewset, using the `APIView` class-based views.

from myapp.negotiation import IgnoreClientContentNegotiation
from myapp.negotiation import IgnoreClientContentNegotiation
from rest_framework.response import Response
from rest_framework.views import APIView

7 changes: 3 additions & 4 deletions docs/api-guide/exceptions.md
Original file line number Diff line number Diff line change
@@ -101,7 +101,7 @@ Note that the exception handler will only be called for responses generated by r

The **base class** for all exceptions raised inside an `APIView` class or `@api_view`.

To provide a custom exception, subclass `APIException` and set the `.status_code`, `.default_detail`, and `default_code` attributes on the class.
To provide a custom exception, subclass `APIException` and set the `.status_code`, `.default_detail`, and `.default_code` attributes on the class.

For example, if your API relies on a third party service that may sometimes be unreachable, you might want to implement an exception for the "503 Service Unavailable" HTTP response code. You could do this like so:

@@ -179,7 +179,7 @@ By default this exception results in a response with the HTTP status code "403 F

**Signature:** `NotFound(detail=None, code=None)`

Raised when a resource does not exists at the given URL. This exception is equivalent to the standard `Http404` Django exception.
Raised when a resource does not exist at the given URL. This exception is equivalent to the standard `Http404` Django exception.

By default this exception results in a response with the HTTP status code "404 Not Found".

@@ -217,11 +217,10 @@ By default this exception results in a response with the HTTP status code "429 T

## ValidationError

**Signature:** `ValidationError(detail, code=None)`
**Signature:** `ValidationError(detail=None, code=None)`

The `ValidationError` exception is slightly different from the other `APIException` classes:

* The `detail` argument is mandatory, not optional.
* The `detail` argument may be a list or dictionary of error details, and may also be a nested data structure. By using a dictionary, you can specify field-level errors while performing object-level validation in the `validate()` method of a serializer. For example. `raise serializers.ValidationError({'name': 'Please enter a valid name.'})`
* By convention you should import the serializers module and use a fully qualified `ValidationError` style, in order to differentiate it from Django's built-in validation error. For example. `raise serializers.ValidationError('This field must be an integer value.')`

131 changes: 69 additions & 62 deletions docs/api-guide/fields.md

Large diffs are not rendered by default.

31 changes: 13 additions & 18 deletions docs/api-guide/filtering.md
Original file line number Diff line number Diff line change
@@ -213,19 +213,23 @@ This will allow the client to filter the items in the list by making queries suc
You can also perform a related lookup on a ForeignKey or ManyToManyField with the lookup API double-underscore notation:

search_fields = ['username', 'email', 'profile__profession']

For [JSONField][JSONField] and [HStoreField][HStoreField] fields you can filter based on nested values within the data structure using the same double-underscore notation:

search_fields = ['data__breed', 'data__owner__other_pets__0__name']

By default, searches will use case-insensitive partial matches. The search parameter may contain multiple search terms, which should be whitespace and/or comma separated. If multiple search terms are used then objects will be returned in the list only if all the provided terms are matched.
By default, searches will use case-insensitive partial matches. The search parameter may contain multiple search terms, which should be whitespace and/or comma separated. If multiple search terms are used then objects will be returned in the list only if all the provided terms are matched. Searches may contain _quoted phrases_ with spaces, each phrase is considered as a single search term.


The search behavior may be restricted by prepending various characters to the `search_fields`.
The search behavior may be specified by prefixing field names in `search_fields` with one of the following characters (which is equivalent to adding `__<lookup>` to the field):

* '^' Starts-with search.
* '=' Exact matches.
* '@' Full-text search. (Currently only supported Django's [PostgreSQL backend][postgres-search].)
* '$' Regex search.
| Prefix | Lookup | |
| ------ | --------------| ------------------ |
| `^` | `istartswith` | Starts-with search.|
| `=` | `iexact` | Exact matches. |
| `$` | `iregex` | Regex search. |
| `@` | `search` | Full-text search (Currently only supported Django's [PostgreSQL backend][postgres-search]). |
| None | `icontains` | Contains search (Default). |

For example:

@@ -253,7 +257,7 @@ The `OrderingFilter` class supports simple query parameter controlled ordering o

![Ordering Filter](../img/ordering-filter.png)

By default, the query parameter is named `'ordering'`, but this may by overridden with the `ORDERING_PARAM` setting.
By default, the query parameter is named `'ordering'`, but this may be overridden with the `ORDERING_PARAM` setting.

For example, to order users by username:

@@ -269,7 +273,7 @@ Multiple orderings may also be specified:

### Specifying which fields may be ordered against

It's recommended that you explicitly specify which fields the API should allowing in the ordering filter. You can do this by setting an `ordering_fields` attribute on the view, like so:
It's recommended that you explicitly specify which fields the API should allow in the ordering filter. You can do this by setting an `ordering_fields` attribute on the view, like so:

class UserListView(generics.ListAPIView):
queryset = User.objects.all()
@@ -335,15 +339,6 @@ Generic filters may also present an interface in the browsable API. To do so you

The method should return a rendered HTML string.

## Filtering & schemas

You can also make the filter controls available to the schema autogeneration
that REST framework provides, by implementing a `get_schema_fields()` method. This method should have the following signature:

`get_schema_fields(self, view)`

The method should return a list of `coreapi.Field` instances.

# Third party packages

The following third party packages provide additional filter implementations.
4 changes: 2 additions & 2 deletions docs/api-guide/format-suffixes.md
Original file line number Diff line number Diff line change
@@ -23,8 +23,8 @@ Returns a URL pattern list which includes format suffix patterns appended to eac
Arguments:

* **urlpatterns**: Required. A URL pattern list.
* **suffix_required**: Optional. A boolean indicating if suffixes in the URLs should be optional or mandatory. Defaults to `False`, meaning that suffixes are optional by default.
* **allowed**: Optional. A list or tuple of valid format suffixes. If not provided, a wildcard format suffix pattern will be used.
* **suffix_required**: Optional. A boolean indicating if suffixes in the URLs should be optional or mandatory. Defaults to `False`, meaning that suffixes are optional by default.
* **allowed**: Optional. A list or tuple of valid format suffixes. If not provided, a wildcard format suffix pattern will be used.

Example:

2 changes: 1 addition & 1 deletion docs/api-guide/generic-views.md
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ For example:

---

**Note:** If the serializer_class used in the generic view spans orm relations, leading to an n+1 problem, you could optimize your queryset in this method using `select_related` and `prefetch_related`. To get more information about n+1 problem and use cases of the mentioned methods refer to related section in [django documentation][django-docs-select-related].
**Note:** If the `serializer_class` used in the generic view spans orm relations, leading to an n+1 problem, you could optimize your queryset in this method using `select_related` and `prefetch_related`. To get more information about n+1 problem and use cases of the mentioned methods refer to related section in [django documentation][django-docs-select-related].

---

15 changes: 3 additions & 12 deletions docs/api-guide/pagination.md
Original file line number Diff line number Diff line change
@@ -227,7 +227,7 @@ Note that the `paginate_queryset` method may set state on the pagination instanc

## Example

Suppose we want to replace the default pagination output style with a modified format that includes the next and previous links under in a nested 'links' key. We could specify a custom pagination class like so:
Suppose we want to replace the default pagination output style with a modified format that includes the next and previous links under in a nested 'links' key. We could specify a custom pagination class like so:

class CustomPagination(pagination.PageNumberPagination):
def get_paginated_response(self, data):
@@ -240,7 +240,7 @@ Suppose we want to replace the default pagination output style with a modified f
'results': data
})

We'd then need to setup the custom class in our configuration:
We'd then need to set up the custom class in our configuration:

REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination',
@@ -262,16 +262,7 @@ API responses for list endpoints will now include a `Link` header, instead of in

![Link Header][link-header]

*A custom pagination style, using the 'Link' header'*

## Pagination & schemas

You can also make the pagination controls available to the schema autogeneration
that REST framework provides, by implementing a `get_schema_fields()` method. This method should have the following signature:

`get_schema_fields(self, view)`

The method should return a list of `coreapi.Field` instances.
*A custom pagination style, using the 'Link' header*

---

6 changes: 3 additions & 3 deletions docs/api-guide/parsers.md
Original file line number Diff line number Diff line change
@@ -11,11 +11,11 @@ sending more complex data than simple forms
>
> &mdash; Malcom Tredinnick, [Django developers group][cite]
REST framework includes a number of built in Parser classes, that allow you to accept requests with various media types. There is also support for defining your own custom parsers, which gives you the flexibility to design the media types that your API accepts.
REST framework includes a number of built-in Parser classes, that allow you to accept requests with various media types. There is also support for defining your own custom parsers, which gives you the flexibility to design the media types that your API accepts.

## How the parser is determined

The set of valid parsers for a view is always defined as a list of classes. When `request.data` is accessed, REST framework will examine the `Content-Type` header on the incoming request, and determine which parser to use to parse the request content.
The set of valid parsers for a view is always defined as a list of classes. When `request.data` is accessed, REST framework will examine the `Content-Type` header on the incoming request, and determine which parser to use to parse the request content.

---

@@ -87,7 +87,7 @@ You will typically want to use both `FormParser` and `MultiPartParser` together

## MultiPartParser

Parses multipart HTML form content, which supports file uploads. Both `request.data` will be populated with a `QueryDict`.
Parses multipart HTML form content, which supports file uploads. `request.data` and `request.FILES` will be populated with a `QueryDict` and `MultiValueDict` respectively.

You will typically want to use both `FormParser` and `MultiPartParser` together in order to fully support HTML form data.

13 changes: 9 additions & 4 deletions docs/api-guide/permissions.md
Original file line number Diff line number Diff line change
@@ -165,7 +165,7 @@ This permission is suitable if you want your API to only be accessible to a subs

## IsAuthenticatedOrReadOnly

The `IsAuthenticatedOrReadOnly` will allow authenticated users to perform any request. Requests for unauthorised users will only be permitted if the request method is one of the "safe" methods; `GET`, `HEAD` or `OPTIONS`.
The `IsAuthenticatedOrReadOnly` will allow authenticated users to perform any request. Requests for unauthenticated users will only be permitted if the request method is one of the "safe" methods; `GET`, `HEAD` or `OPTIONS`.

This permission is suitable if you want to your API to allow read permissions to anonymous users, and only allow write permissions to authenticated users.

@@ -177,7 +177,7 @@ This permission class ties into Django's standard `django.contrib.auth` [model p
* `PUT` and `PATCH` requests require the user to have the `change` permission on the model.
* `DELETE` requests require the user to have the `delete` permission on the model.

The default behaviour can also be overridden to support custom model permissions. For example, you might want to include a `view` model permission for `GET` requests.
The default behavior can also be overridden to support custom model permissions. For example, you might want to include a `view` model permission for `GET` requests.

To use custom model permissions, override `DjangoModelPermissions` and set the `.perms_map` property. Refer to the source code for details.

@@ -201,7 +201,7 @@ As with `DjangoModelPermissions` you can use custom model permissions by overrid

---

**Note**: If you need object level `view` permissions for `GET`, `HEAD` and `OPTIONS` requests and are using django-guardian for your object-level permissions backend, you'll want to consider using the `DjangoObjectPermissionsFilter` class provided by the [`djangorestframework-guardian` package][django-rest-framework-guardian]. It ensures that list endpoints only return results including objects for which the user has appropriate view permissions.
**Note**: If you need object level `view` permissions for `GET`, `HEAD` and `OPTIONS` requests and are using django-guardian for your object-level permissions backend, you'll want to consider using the `DjangoObjectPermissionsFilter` class provided by the [`djangorestframework-guardian2` package][django-rest-framework-guardian2]. It ensures that list endpoints only return results including objects for which the user has appropriate view permissions.

---

@@ -324,6 +324,10 @@ The [DRY Rest Permissions][dry-rest-permissions] package provides the ability to

The [Django Rest Framework Roles][django-rest-framework-roles] package makes it easier to parameterize your API over multiple types of users.

## Rest Framework Roles

The [Rest Framework Roles][rest-framework-roles] makes it super easy to protect views based on roles. Most importantly allows you to decouple accessibility logic from models and views in a clean human-readable way.

## Django REST Framework API Key

The [Django REST Framework API Key][djangorestframework-api-key] package provides permissions classes, models and helpers to add API key authorization to your API. It can be used to authorize internal or third-party backends and services (i.e. _machines_) which do not have a user account. API keys are stored securely using Django's password hashing infrastructure, and they can be viewed, edited and revoked at anytime in the Django admin.
@@ -349,8 +353,9 @@ The [Django Rest Framework PSQ][drf-psq] package is an extension that gives supp
[rest-condition]: https://github.com/caxap/rest_condition
[dry-rest-permissions]: https://github.com/FJNR-inc/dry-rest-permissions
[django-rest-framework-roles]: https://github.com/computer-lab/django-rest-framework-roles
[rest-framework-roles]: https://github.com/Pithikos/rest-framework-roles
[djangorestframework-api-key]: https://florimondmanca.github.io/djangorestframework-api-key/
[django-rest-framework-role-filters]: https://github.com/allisson/django-rest-framework-role-filters
[django-rest-framework-guardian]: https://github.com/rpkilby/django-rest-framework-guardian
[django-rest-framework-guardian2]: https://github.com/johnthagen/django-rest-framework-guardian2
[drf-access-policy]: https://github.com/rsinger86/drf-access-policy
[drf-psq]: https://github.com/drf-psq/drf-psq
10 changes: 5 additions & 5 deletions docs/api-guide/relations.md
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ For example, the following serializer would lead to a database hit each time eva
class Meta:
model = Album
fields = ['album_name', 'artist', 'tracks']

# For each album object, tracks should be fetched from database
qs = Album.objects.all()
print(AlbumSerializer(qs, many=True).data)
@@ -246,7 +246,7 @@ When using `SlugRelatedField` as a read-write field, you will normally want to e

## HyperlinkedIdentityField

This field can be applied as an identity relationship, such as the `'url'` field on a HyperlinkedModelSerializer. It can also be used for an attribute on the object. For example, the following serializer:
This field can be applied as an identity relationship, such as the `'url'` field on a HyperlinkedModelSerializer. It can also be used for an attribute on the object. For example, the following serializer:

class AlbumSerializer(serializers.HyperlinkedModelSerializer):
track_listing = serializers.HyperlinkedIdentityField(view_name='track-list')
@@ -278,7 +278,7 @@ This field is always read-only.

As opposed to previously discussed _references_ to another entity, the referred entity can instead also be embedded or _nested_
in the representation of the object that refers to it.
Such nested relationships can be expressed by using serializers as fields.
Such nested relationships can be expressed by using serializers as fields.

If the field is used to represent a to-many relationship, you should add the `many=True` flag to the serializer field.

@@ -494,8 +494,8 @@ This behavior is intended to prevent a template from being unable to render in a

There are two keyword arguments you can use to control this behavior:

- `html_cutoff` - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Set to `None` to disable any limiting. Defaults to `1000`.
- `html_cutoff_text` - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to `"More than {count} items…"`
* `html_cutoff` - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Set to `None` to disable any limiting. Defaults to `1000`.
* `html_cutoff_text` - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to `"More than {count} items…"`

You can also control these globally using the settings `HTML_SELECT_CUTOFF` and `HTML_SELECT_CUTOFF_TEXT`.

10 changes: 5 additions & 5 deletions docs/api-guide/renderers.md
Original file line number Diff line number Diff line change
@@ -105,7 +105,7 @@ The TemplateHTMLRenderer will create a `RequestContext`, using the `response.dat

---

**Note:** When used with a view that makes use of a serializer the `Response` sent for rendering may not be a dictionary and will need to be wrapped in a dict before returning to allow the TemplateHTMLRenderer to render it. For example:
**Note:** When used with a view that makes use of a serializer the `Response` sent for rendering may not be a dictionary and will need to be wrapped in a dict before returning to allow the `TemplateHTMLRenderer` to render it. For example:

```
response.data = {'results': response.data}
@@ -192,7 +192,7 @@ By default the response content will be rendered with the highest priority rende
def get_default_renderer(self, view):
return JSONRenderer()

## AdminRenderer
## AdminRenderer

Renders data into HTML for an admin-like display:

@@ -283,7 +283,7 @@ By default this will include the following keys: `view`, `request`, `response`,

The following is an example plaintext renderer that will return a response with the `data` parameter as the content of the response.

from django.utils.encoding import smart_text
from django.utils.encoding import smart_str
from rest_framework import renderers


@@ -292,7 +292,7 @@ The following is an example plaintext renderer that will return a response with
format = 'txt'

def render(self, data, accepted_media_type=None, renderer_context=None):
return smart_text(data, encoding=self.charset)
return smart_str(data, encoding=self.charset)

## Setting the character set

@@ -332,7 +332,7 @@ You can do some pretty flexible things using REST framework's renderers. Some e
* Specify multiple types of HTML representation for API clients to use.
* Underspecify a renderer's media type, such as using `media_type = 'image/*'`, and use the `Accept` header to vary the encoding of the response.

## Varying behaviour by media type
## Varying behavior by media type

In some cases you might want your view to use different serialization styles depending on the accepted media type. If you need to do this you can access `request.accepted_renderer` to determine the negotiated renderer that will be used for the response.

2 changes: 1 addition & 1 deletion docs/api-guide/requests.md
Original file line number Diff line number Diff line change
@@ -49,7 +49,7 @@ If a client sends a request with a content-type that cannot be parsed then a `Un

# Content negotiation

The request exposes some properties that allow you to determine the result of the content negotiation stage. This allows you to implement behaviour such as selecting a different serialization schemes for different media types.
The request exposes some properties that allow you to determine the result of the content negotiation stage. This allows you to implement behavior such as selecting a different serialization schemes for different media types.

## .accepted_renderer

22 changes: 11 additions & 11 deletions docs/api-guide/reverse.md
Original file line number Diff line number Diff line change
@@ -32,16 +32,16 @@ You should **include the request as a keyword argument** to the function, for ex

from rest_framework.reverse import reverse
from rest_framework.views import APIView
from django.utils.timezone import now

class APIRootView(APIView):
def get(self, request):
year = now().year
data = {
...
'year-summary-url': reverse('year-summary', args=[year], request=request)
from django.utils.timezone import now

class APIRootView(APIView):
def get(self, request):
year = now().year
data = {
...
'year-summary-url': reverse('year-summary', args=[year], request=request)
}
return Response(data)
return Response(data)

## reverse_lazy

@@ -54,5 +54,5 @@ As with the `reverse` function, you should **include the request as a keyword ar
api_root = reverse_lazy('api-root', request=request)

[cite]: https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5
[reverse]: https://docs.djangoproject.com/en/stable/topics/http/urls/#reverse
[reverse-lazy]: https://docs.djangoproject.com/en/stable/topics/http/urls/#reverse-lazy
[reverse]: https://docs.djangoproject.com/en/stable/ref/urlresolvers/#reverse
[reverse-lazy]: https://docs.djangoproject.com/en/stable/ref/urlresolvers/#reverse-lazy
15 changes: 14 additions & 1 deletion docs/api-guide/routers.md
Original file line number Diff line number Diff line change
@@ -167,12 +167,23 @@ This behavior can be modified by setting the `trailing_slash` argument to `False

Trailing slashes are conventional in Django, but are not used by default in some other frameworks such as Rails. Which style you choose to use is largely a matter of preference, although some javascript frameworks may expect a particular routing style.

The router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the `lookup_value_regex` attribute on the viewset. For example, you can limit the lookup to valid UUIDs:
By default the URLs created by `SimpleRouter` use regular expressions. This behavior can be modified by setting the `use_regex_path` argument to `False` when instantiating the router, in this case [path converters][path-converters-topic-reference] are used. For example:

router = SimpleRouter(use_regex_path=False)

**Note**: `use_regex_path=False` only works with Django 2.x or above, since this feature was introduced in 2.0.0. See [release note][simplified-routing-release-note]


The router will match lookup values containing any characters except slashes and period characters. For a more restrictive (or lenient) lookup pattern, set the `lookup_value_regex` attribute on the viewset or `lookup_value_converter` if using path converters. For example, you can limit the lookup to valid UUIDs:

class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_id'
lookup_value_regex = '[0-9a-f]{32}'

class MyPathModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
lookup_field = 'my_model_uuid'
lookup_value_converter = 'uuid'

## DefaultRouter

This router is similar to `SimpleRouter` as above, but additionally includes a default API root view, that returns a response containing hyperlinks to all the list views. It also generates routes for optional `.json` style format suffixes.
@@ -340,3 +351,5 @@ The [`DRF-extensions` package][drf-extensions] provides [routers][drf-extensions
[drf-extensions-customizable-endpoint-names]: https://chibisov.github.io/drf-extensions/docs/#controller-endpoint-name
[url-namespace-docs]: https://docs.djangoproject.com/en/4.0/topics/http/urls/#url-namespaces
[include-api-reference]: https://docs.djangoproject.com/en/4.0/ref/urls/#include
[simplified-routing-release-note]: https://docs.djangoproject.com/en/2.0/releases/2.0/#simplified-url-routing-syntax
[path-converters-topic-reference]: https://docs.djangoproject.com/en/2.0/topics/http/urls/#path-converters
52 changes: 39 additions & 13 deletions docs/api-guide/schemas.md
Original file line number Diff line number Diff line change
@@ -9,6 +9,23 @@ source:
>
> &mdash; Heroku, [JSON Schema for the Heroku Platform API][cite]
---

**Deprecation notice:**

REST framework's built-in support for generating OpenAPI schemas is
**deprecated** in favor of 3rd party packages that can provide this
functionality instead. The built-in support will be moved into a separate
package and then subsequently retired over the next releases.

As a full-fledged replacement, we recommend the [drf-spectacular] package.
It has extensive support for generating OpenAPI 3 schemas from
REST framework APIs, with both automatic and customisable options available.
For further information please refer to
[Documenting your API](../topics/documenting-your-api.md#drf-spectacular).

---

API schemas are a useful tool that allow for a range of use cases, including
generating reference documentation, or driving dynamic client libraries that
can interact with your API.
@@ -39,10 +56,11 @@ The following sections explain more.

### Install dependencies

pip install pyyaml uritemplate
pip install pyyaml uritemplate inflection

* `pyyaml` is used to generate schema into YAML-based OpenAPI format.
* `uritemplate` is used internally to get parameters in path.
* `inflection` is used to pluralize operations more appropriately in the list endpoints.

### Generating a static schema with the `generateschema` management command

@@ -77,11 +95,13 @@ urlpatterns = [
# Use the `get_schema_view()` helper to add a `SchemaView` to project URLs.
# * `title` and `description` parameters are passed to `SchemaGenerator`.
# * Provide view name for use with `reverse()`.
path('openapi', get_schema_view(
title="Your Project",
description="API for all things …",
version="1.0.0"
), name='openapi-schema'),
path(
"openapi",
get_schema_view(
title="Your Project", description="API for all things …", version="1.0.0"
),
name="openapi-schema",
),
# ...
]
```
@@ -122,6 +142,7 @@ The `get_schema_view()` helper takes the following keyword arguments:
url='https://www.example.org/api/',
patterns=schema_url_patterns,
)
* `public`: May be used to specify if schema should bypass views permissions. Default to False

* `generator_class`: May be used to specify a `SchemaGenerator` subclass to be
passed to the `SchemaView`.
@@ -241,11 +262,13 @@ class CustomSchema(AutoSchema):
"""
AutoSchema subclass using schema_extra_info on the view.
"""

...


class CustomView(APIView):
schema = CustomSchema()
schema_extra_info = ... some extra info ...
schema_extra_info = ... # some extra info
```

Here, the `AutoSchema` subclass goes looking for `schema_extra_info` on the
@@ -260,10 +283,13 @@ class BaseSchema(AutoSchema):
"""
AutoSchema subclass that knows how to use extra_info.
"""

...


class CustomSchema(BaseSchema):
extra_info = ... some extra info ...
extra_info = ... # some extra info


class CustomView(APIView):
schema = CustomSchema()
@@ -284,23 +310,22 @@ class CustomSchema(BaseSchema):
self.extra_info = kwargs.pop("extra_info")
super().__init__(**kwargs)


class CustomView(APIView):
schema = CustomSchema(
extra_info=... some extra info ...
)
schema = CustomSchema(extra_info=...) # some extra info
```

This saves you having to create a custom subclass per-view for a commonly used option.

Not all `AutoSchema` methods expose related `__init__()` kwargs, but those for
Not all `AutoSchema` methods expose related `__init__()` kwargs, but those for
the more commonly needed options do.

### `AutoSchema` methods

#### `get_components()`

Generates the OpenAPI components that describe request and response bodies,
deriving their properties from the serializer.
deriving their properties from the serializer.

Returns a dictionary mapping the component name to the generated
representation. By default this has just a single pair but you may override
@@ -437,3 +462,4 @@ create a base `AutoSchema` subclass for your project that takes additional
[openapi-generator]: https://github.com/OpenAPITools/openapi-generator
[swagger-codegen]: https://github.com/swagger-api/swagger-codegen
[info-object]: https://swagger.io/specification/#infoObject
[drf-spectacular]: https://drf-spectacular.readthedocs.io/en/latest/readme.html
42 changes: 20 additions & 22 deletions docs/api-guide/serializers.md
Original file line number Diff line number Diff line change
@@ -226,7 +226,7 @@ Individual fields on a serializer can include validators, by declaring them on t
raise serializers.ValidationError('Not a multiple of ten')

class GameRecord(serializers.Serializer):
score = IntegerField(validators=[multiple_of_ten])
score = serializers.IntegerField(validators=[multiple_of_ten])
...

Serializer classes can also include reusable validators that are applied to the complete set of field data. These validators are included by declaring them on an inner `Meta` class, like so:
@@ -594,25 +594,25 @@ The ModelSerializer class also exposes an API that you can override in order to

Normally if a `ModelSerializer` does not generate the fields you need by default then you should either add them to the class explicitly, or simply use a regular `Serializer` class instead. However in some cases you may want to create a new base class that defines how the serializer fields are created for any given model.

### `.serializer_field_mapping`
### `serializer_field_mapping`

A mapping of Django model fields to REST framework serializer fields. You can override this mapping to alter the default serializer fields that should be used for each model field.

### `.serializer_related_field`
### `serializer_related_field`

This property should be the serializer field class, that is used for relational fields by default.

For `ModelSerializer` this defaults to `serializers.PrimaryKeyRelatedField`.

For `HyperlinkedModelSerializer` this defaults to `serializers.HyperlinkedRelatedField`.

### `.serializer_url_field`
### `serializer_url_field`

The serializer field class that should be used for any `url` field on the serializer.

Defaults to `serializers.HyperlinkedIdentityField`

### `.serializer_choice_field`
### `serializer_choice_field`

The serializer field class that should be used for any choice fields on the serializer.

@@ -622,21 +622,21 @@ Defaults to `serializers.ChoiceField`

The following methods are called to determine the class and keyword arguments for each field that should be automatically included on the serializer. Each of these methods should return a two tuple of `(field_class, field_kwargs)`.

### `.build_standard_field(self, field_name, model_field)`
### `build_standard_field(self, field_name, model_field)`

Called to generate a serializer field that maps to a standard model field.

The default implementation returns a serializer class based on the `serializer_field_mapping` attribute.

### `.build_relational_field(self, field_name, relation_info)`
### `build_relational_field(self, field_name, relation_info)`

Called to generate a serializer field that maps to a relational model field.

The default implementation returns a serializer class based on the `serializer_related_field` attribute.

The `relation_info` argument is a named tuple, that contains `model_field`, `related_model`, `to_many` and `has_through_model` properties.

### `.build_nested_field(self, field_name, relation_info, nested_depth)`
### `build_nested_field(self, field_name, relation_info, nested_depth)`

Called to generate a serializer field that maps to a relational model field, when the `depth` option has been set.

@@ -646,17 +646,17 @@ The `nested_depth` will be the value of the `depth` option, minus one.

The `relation_info` argument is a named tuple, that contains `model_field`, `related_model`, `to_many` and `has_through_model` properties.

### `.build_property_field(self, field_name, model_class)`
### `build_property_field(self, field_name, model_class)`

Called to generate a serializer field that maps to a property or zero-argument method on the model class.

The default implementation returns a `ReadOnlyField` class.

### `.build_url_field(self, field_name, model_class)`
### `build_url_field(self, field_name, model_class)`

Called to generate a serializer field for the serializer's own `url` field. The default implementation returns a `HyperlinkedIdentityField` class.

### `.build_unknown_field(self, field_name, model_class)`
### `build_unknown_field(self, field_name, model_class)`

Called when the field name did not map to any model field or model property.
The default implementation raises an error, although subclasses may customize this behavior.
@@ -758,11 +758,11 @@ This is `True` by default, but can be set to `False` if you want to disallow emp

### `max_length`

This is `None` by default, but can be set to a positive integer if you want to validates that the list contains no more than this number of elements.
This is `None` by default, but can be set to a positive integer if you want to validate that the list contains no more than this number of elements.

### `min_length`

This is `None` by default, but can be set to a positive integer if you want to validates that the list contains no fewer than this number of elements.
This is `None` by default, but can be set to a positive integer if you want to validate that the list contains no fewer than this number of elements.

### Customizing `ListSerializer` behavior

@@ -845,8 +845,6 @@ Here's an example of how you might choose to implement multiple updates:
class Meta:
list_serializer_class = BookListSerializer

It is possible that a third party package may be included alongside the 3.1 release that provides some automatic support for multiple update operations, similar to the `allow_add_remove` behavior that was present in REST framework 2.

#### Customizing ListSerializer initialization

When a serializer with `many=True` is instantiated, we need to determine which arguments and keyword arguments should be passed to the `.__init__()` method for both the child `Serializer` class, and for the parent `ListSerializer` class.
@@ -910,15 +908,15 @@ We can now use this class to serialize single `HighScore` instances:
def high_score(request, pk):
instance = HighScore.objects.get(pk=pk)
serializer = HighScoreSerializer(instance)
return Response(serializer.data)
return Response(serializer.data)

Or use it to serialize multiple instances:

@api_view(['GET'])
def all_high_scores(request):
queryset = HighScore.objects.order_by('-score')
serializer = HighScoreSerializer(queryset, many=True)
return Response(serializer.data)
return Response(serializer.data)

#### Read-write `BaseSerializer` classes

@@ -949,8 +947,8 @@ Here's a complete example of our previous `HighScoreSerializer`, that's been upd
'player_name': 'May not be more than 10 characters.'
})

# Return the validated values. This will be available as
# the `.validated_data` property.
# Return the validated values. This will be available as
# the `.validated_data` property.
return {
'score': int(score),
'player_name': player_name
@@ -1021,7 +1019,7 @@ Some reasons this might be useful include...

The signatures for these methods are as follows:

#### `.to_representation(self, instance)`
#### `to_representation(self, instance)`

Takes the object instance that requires serialization, and should return a primitive representation. Typically this means returning a structure of built-in Python datatypes. The exact types that can be handled will depend on the render classes you have configured for your API.

@@ -1033,7 +1031,7 @@ May be overridden in order to modify the representation style. For example:
ret['username'] = ret['username'].lower()
return ret

#### ``.to_internal_value(self, data)``
#### ``to_internal_value(self, data)``

Takes the unvalidated incoming data as input and should return the validated data that will be made available as `serializer.validated_data`. The return value will also be passed to the `.create()` or `.update()` methods if `.save()` is called on the serializer class.

@@ -1189,7 +1187,7 @@ The [drf-writable-nested][drf-writable-nested] package provides writable nested

## DRF Encrypt Content

The [drf-encrypt-content][drf-encrypt-content] package helps you encrypt your data, serialized through ModelSerializer. It also contains some helper functions. Which helps you to encrypt your data.
The [drf-encrypt-content][drf-encrypt-content] package helps you encrypt your data, serialized through ModelSerializer. It also contains some helper functions. Which helps you to encrypt your data.


[cite]: https://groups.google.com/d/topic/django-users/sVFaOfQi4wY/discussion
6 changes: 6 additions & 0 deletions docs/api-guide/settings.md
Original file line number Diff line number Diff line change
@@ -163,6 +163,12 @@ The string that should used for any versioning parameters, such as in the media

Default: `'version'`

#### DEFAULT_VERSIONING_CLASS

The default versioning scheme to use.

Default: `None`

---

## Authentication settings
4 changes: 4 additions & 0 deletions docs/api-guide/status-codes.md
Original file line number Diff line number Diff line change
@@ -41,6 +41,8 @@ This class of status code indicates a provisional response. There are no 1xx st

HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
HTTP_102_PROCESSING
HTTP_103_EARLY_HINTS

## Successful - 2xx

@@ -93,9 +95,11 @@ The 4xx class of status code is intended for cases in which the client seems to
HTTP_415_UNSUPPORTED_MEDIA_TYPE
HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE
HTTP_417_EXPECTATION_FAILED
HTTP_421_MISDIRECTED_REQUEST
HTTP_422_UNPROCESSABLE_ENTITY
HTTP_423_LOCKED
HTTP_424_FAILED_DEPENDENCY
HTTP_425_TOO_EARLY
HTTP_426_UPGRADE_REQUIRED
HTTP_428_PRECONDITION_REQUIRED
HTTP_429_TOO_MANY_REQUESTS
4 changes: 2 additions & 2 deletions docs/api-guide/throttling.md
Original file line number Diff line number Diff line change
@@ -50,9 +50,9 @@ The rate descriptions used in `DEFAULT_THROTTLE_RATES` may include `second`, `mi
You can also set the throttling policy on a per-view or per-viewset basis,
using the `APIView` class-based views.

from rest_framework.response import Response
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
from rest_framework.views import APIView

class ExampleView(APIView):
throttle_classes = [UserRateThrottle]
29 changes: 17 additions & 12 deletions docs/api-guide/validators.md
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ Validation in Django REST framework serializers is handled a little differently
With `ModelForm` the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class. This is advantageous for the following reasons:

* It introduces a proper separation of concerns, making your code behavior more obvious.
* It is easy to switch between using shortcut `ModelSerializer` classes and using explicit `Serializer` classes. Any validation behavior being used for `ModelSerializer` is simple to replicate.
* It is easy to switch between using shortcut `ModelSerializer` classes and using explicit `Serializer` classes. Any validation behavior being used for `ModelSerializer` is simple to replicate.
* Printing the `repr` of a serializer instance will show you exactly what validation rules it applies. There's no extra hidden validation behavior being called on the model instance.

When you're using `ModelSerializer` all of this is handled automatically for you. If you want to drop down to using `Serializer` classes instead, then you need to define the validation rules explicitly.
@@ -53,7 +53,7 @@ If we open up the Django shell using `manage.py shell` we can now

The interesting bit here is the `reference` field. We can see that the uniqueness constraint is being explicitly enforced by a validator on the serializer field.

Because of this more explicit style REST framework includes a few validator classes that are not available in core Django. These classes are detailed below.
Because of this more explicit style REST framework includes a few validator classes that are not available in core Django. These classes are detailed below. REST framework validators, like their Django counterparts, implement the `__eq__` method, allowing you to compare instances for equality.

---

@@ -164,14 +164,18 @@ If you want the date field to be entirely hidden from the user, then use `Hidden

---

---

**Note:** `HiddenField()` does not appear in `partial=True` serializer (when making `PATCH` request). This behavior might change in future, follow updates on [github discussion](https://github.com/encode/django-rest-framework/discussions/8259).

---

# Advanced field defaults

Validators that are applied across multiple fields in the serializer can sometimes require a field input that should not be provided by the API client, but that *is* available as input to the validator.
For this purposes use `HiddenField`. This field will be present in `validated_data` but *will not* be used in the serializer output representation.

Two patterns that you may want to use for this sort of validation include:

* Using `HiddenField`. This field will be present in `validated_data` but *will not* be used in the serializer output representation.
* Using a standard field with `read_only=True`, but that also includes a `default=…` argument. This field *will* be used in the serializer output representation, but cannot be set directly by the user.
**Note:** Using a `read_only=True` field is excluded from writable fields so it won't use a `default=…` argument. Look [3.8 announcement](https://www.django-rest-framework.org/community/3.8-announcement/#altered-the-behaviour-of-read_only-plus-default-on-field).

REST framework includes a couple of defaults that may be useful in this context.

@@ -183,7 +187,7 @@ A default class that can be used to represent the current user. In order to use
default=serializers.CurrentUserDefault()
)

#### CreateOnlyDefault
#### CreateOnlyDefault

A default class that can be used to *only set a default argument during create operations*. During updates the field is omitted.

@@ -208,7 +212,7 @@ by specifying an empty list for the serializer `Meta.validators` attribute.

By default "unique together" validation enforces that all fields be
`required=True`. In some cases, you might want to explicit apply
`required=False` to one of the fields, in which case the desired behaviour
`required=False` to one of the fields, in which case the desired behavior
of the validation is ambiguous.

In this case you will typically need to exclude the validator from the
@@ -295,13 +299,14 @@ To write a class-based validator, use the `__call__` method. Class-based validat

In some advanced cases you might want a validator to be passed the serializer
field it is being used with as additional context. You can do so by setting
a `requires_context = True` attribute on the validator. The `__call__` method
a `requires_context = True` attribute on the validator class. The `__call__` method
will then be called with the `serializer_field`
or `serializer` as an additional argument.

requires_context = True
class MultipleOf:
requires_context = True

def __call__(self, value, serializer_field):
...
def __call__(self, value, serializer_field):
...

[cite]: https://docs.djangoproject.com/en/stable/ref/validators/
2 changes: 1 addition & 1 deletion docs/api-guide/views.md
Original file line number Diff line number Diff line change
@@ -153,7 +153,7 @@ The core of this functionality is the `api_view` decorator, which takes a list o

This view will use the default renderers, parsers, authentication classes etc specified in the [settings].

By default only `GET` methods will be accepted. Other methods will respond with "405 Method Not Allowed". To alter this behaviour, specify which methods the view allows, like so:
By default only `GET` methods will be accepted. Other methods will respond with "405 Method Not Allowed". To alter this behavior, specify which methods the view allows, like so:

@api_view(['GET', 'POST'])
def hello_world(request):
38 changes: 23 additions & 15 deletions docs/api-guide/viewsets.md
Original file line number Diff line number Diff line change
@@ -116,7 +116,7 @@ During dispatch, the following attributes are available on the `ViewSet`.
* `name` - the display name for the viewset. This argument is mutually exclusive to `suffix`.
* `description` - the display description for the individual view of a viewset.

You may inspect these attributes to adjust behaviour based on the current action. For example, you could restrict permissions to everything except the `list` action similar to this:
You may inspect these attributes to adjust behavior based on the current action. For example, you could restrict permissions to everything except the `list` action similar to this:

def get_permissions(self):
"""
@@ -178,6 +178,13 @@ The `action` decorator will route `GET` requests by default, but may also accept
def unset_password(self, request, pk=None):
...

Argument `methods` also supports HTTP methods defined as [HTTPMethod](https://docs.python.org/3/library/http.html#http.HTTPMethod). Example below is identical to the one above:

from http import HTTPMethod

@action(detail=True, methods=[HTTPMethod.POST, HTTPMethod.DELETE])
def unset_password(self, request, pk=None):
...

The decorator allows you to override any viewset-level configuration such as `permission_classes`, `serializer_class`, `filter_backends`...:

@@ -194,15 +201,16 @@ To view all extra actions, call the `.get_extra_actions()` method.
Extra actions can map additional HTTP methods to separate `ViewSet` methods. For example, the above password set/unset methods could be consolidated into a single route. Note that additional mappings do not accept arguments.

```python
@action(detail=True, methods=['put'], name='Change Password')
def password(self, request, pk=None):
"""Update the user's password."""
...

@password.mapping.delete
def delete_password(self, request, pk=None):
"""Delete the user's password."""
...
@action(detail=True, methods=["put"], name="Change Password")
def password(self, request, pk=None):
"""Update the user's password."""
...


@password.mapping.delete
def delete_password(self, request, pk=None):
"""Delete the user's password."""
...
```

## Reversing action URLs
@@ -213,14 +221,14 @@ Note that the `basename` is provided by the router during `ViewSet` registration

Using the example from the previous section:

```python
>>> view.reverse_action('set-password', args=['1'])
```pycon
>>> view.reverse_action("set-password", args=["1"])
'http://localhost:8000/api/users/1/set_password'
```

Alternatively, you can use the `url_name` attribute set by the `@action` decorator.

```python
```pycon
>>> view.reverse_action(view.set_password.url_name, args=['1'])
'http://localhost:8000/api/users/1/set_password'
```
@@ -247,7 +255,7 @@ In order to use a `GenericViewSet` class you'll override the class and either mi

The `ModelViewSet` class inherits from `GenericAPIView` and includes implementations for various actions, by mixing in the behavior of the various mixin classes.

The actions provided by the `ModelViewSet` class are `.list()`, `.retrieve()`, `.create()`, `.update()`, `.partial_update()`, and `.destroy()`.
The actions provided by the `ModelViewSet` class are `.list()`, `.retrieve()`, `.create()`, `.update()`, `.partial_update()`, and `.destroy()`.

#### Example

@@ -303,7 +311,7 @@ You may need to provide custom `ViewSet` classes that do not have the full set o

To create a base viewset class that provides `create`, `list` and `retrieve` operations, inherit from `GenericViewSet`, and mixin the required actions:

from rest_framework import mixins
from rest_framework import mixins, viewsets

class CreateListRetrieveViewSet(mixins.CreateModelMixin,
mixins.ListModelMixin,
4 changes: 2 additions & 2 deletions docs/community/3.0-announcement.md
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ Notable features of this new release include:
* Support for overriding how validation errors are handled by your API.
* A metadata API that allows you to customize how `OPTIONS` requests are handled by your API.
* A more compact JSON output with unicode style encoding turned on by default.
* Templated based HTML form rendering for serializers. This will be finalized as public API in the upcoming 3.1 release.
* Templated based HTML form rendering for serializers. This will be finalized as public API in the upcoming 3.1 release.

Significant new functionality continues to be planned for the 3.1 and 3.2 releases. These releases will correspond to the two [Kickstarter stretch goals](https://www.kickstarter.com/projects/tomchristie/django-rest-framework-3) - "Feature improvements" and "Admin interface". Further 3.x releases will present simple upgrades, without the same level of fundamental API changes necessary for the 3.0 release.

@@ -632,7 +632,7 @@ The `MultipleChoiceField` class has been added. This field acts like `ChoiceFiel

The `from_native(self, value)` and `to_native(self, data)` method names have been replaced with the more obviously named `to_internal_value(self, data)` and `to_representation(self, value)`.

The `field_from_native()` and `field_to_native()` methods are removed. Previously you could use these methods if you wanted to customise the behaviour in a way that did not simply lookup the field value from the object. For example...
The `field_from_native()` and `field_to_native()` methods are removed. Previously you could use these methods if you wanted to customise the behavior in a way that did not simply lookup the field value from the object. For example...

def field_to_native(self, obj, field_name):
"""A custom read-only field that returns the class name."""
15 changes: 8 additions & 7 deletions docs/community/3.10-announcement.md
Original file line number Diff line number Diff line change
@@ -41,8 +41,8 @@ update your REST framework settings to include `DEFAULT_SCHEMA_CLASS` explicitly

```python
REST_FRAMEWORK = {
...
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema'
...: ...,
"DEFAULT_SCHEMA_CLASS": "rest_framework.schemas.coreapi.AutoSchema",
}
```

@@ -74,10 +74,11 @@ urlpatterns = [
# Use the `get_schema_view()` helper to add a `SchemaView` to project URLs.
# * `title` and `description` parameters are passed to `SchemaGenerator`.
# * Provide view name for use with `reverse()`.
path('openapi', get_schema_view(
title="Your Project",
description="API for all things …"
), name='openapi-schema'),
path(
"openapi",
get_schema_view(title="Your Project", description="API for all things …"),
name="openapi-schema",
),
# ...
]
```
@@ -142,6 +143,6 @@ continued development by **[signing up for a paid plan][funding]**.

*Many thanks to all our [wonderful sponsors][sponsors], and in particular to our premium backers, [Sentry](https://getsentry.com/welcome/), [Stream](https://getstream.io/?utm_source=drf&utm_medium=banner&utm_campaign=drf), [ESG](https://software.esg-usa.com/), [Rollbar](https://rollbar.com/?utm_source=django&utm_medium=sponsorship&utm_campaign=freetrial), [Cadre](https://cadre.com), [Kloudless](https://hubs.ly/H0f30Lf0), and [Lights On Software](https://lightsonsoftware.com).*

[legacy-core-api-docs]:https://github.com/encode/django-rest-framework/blob/master/docs/coreapi/index.md
[legacy-core-api-docs]:https://github.com/encode/django-rest-framework/blob/3.14.0/docs/coreapi/index.md
[sponsors]: https://fund.django-rest-framework.org/topics/funding/#our-sponsors
[funding]: funding.md
11 changes: 6 additions & 5 deletions docs/community/3.11-announcement.md
Original file line number Diff line number Diff line change
@@ -43,10 +43,11 @@ be extracted from the class docstring:

```python
class DocStringExampleListView(APIView):
"""
get: A description of my GET operation.
post: A description of my POST operation.
"""
"""
get: A description of my GET operation.
post: A description of my POST operation.
"""

permission_classes = [permissions.IsAuthenticatedOrReadOnly]

def get(self, request, *args, **kwargs):
@@ -63,7 +64,7 @@ In some circumstances a Validator class or a Default class may need to access th
* Uniqueness validators need to be able to determine the name of the field to which they are applied, in order to run an appropriate database query.
* The `CurrentUserDefault` needs to be able to determine the context with which the serializer was instantiated, in order to return the current user instance.

Previous our approach to this was that implementations could include a `set_context` method, which would be called prior to validation. However this approach had issues with potential race conditions. We have now move this approach into a pending deprecation state. It will continue to function, but will be escalated to a deprecated state in 3.12, and removed entirely in 3.13.
Our previous approach to this was that implementations could include a `set_context` method, which would be called prior to validation. However this approach had issues with potential race conditions. We have now move this approach into a pending deprecation state. It will continue to function, but will be escalated to a deprecated state in 3.12, and removed entirely in 3.13.

Instead, validators or defaults which require the serializer context, should include a `requires_context = True` attribute on the class.

32 changes: 22 additions & 10 deletions docs/community/3.12-announcement.md
Original file line number Diff line number Diff line change
@@ -30,18 +30,18 @@ in the URL path.

For example...

Method | Path | Tags
Method | Path | Tags
--------------------------------|-----------------|-------------
`GET`, `PUT`, `PATCH`, `DELETE` | `/users/{id}/` | `['users']`
`GET`, `POST` | `/users/` | `['users']`
`GET`, `PUT`, `PATCH`, `DELETE` | `/orders/{id}/` | `['orders']`
`GET`, `POST` | `/orders/` | `['orders']`
`GET`, `PUT`, `PATCH`, `DELETE` | `/users/{id}/` | `['users']`
`GET`, `POST` | `/users/` | `['users']`
`GET`, `PUT`, `PATCH`, `DELETE` | `/orders/{id}/` | `['orders']`
`GET`, `POST` | `/orders/` | `['orders']`

The tags used for a particular view may also be overridden...

```python
class MyOrders(APIView):
schema = AutoSchema(tags=['users', 'orders'])
schema = AutoSchema(tags=["users", "orders"])
...
```

@@ -68,7 +68,7 @@ may be overridden if needed](https://www.django-rest-framework.org/api-guide/sch

```python
class MyOrders(APIView):
schema = AutoSchema(component_name="OrderDetails")
schema = AutoSchema(component_name="OrderDetails")
```

## More Public API
@@ -118,10 +118,11 @@ class SitesSearchView(generics.ListAPIView):
by a search against the site name or location. (Location searches are
matched against the region and country names.)
"""

queryset = Sites.objects.all()
serializer_class = SitesSerializer
filter_backends = [filters.SearchFilter]
search_fields = ['site_name', 'location__region', 'location__country']
search_fields = ["site_name", "location__region", "location__country"]
```

### Searches against annotate fields
@@ -135,14 +136,25 @@ class PublisherSearchView(generics.ListAPIView):
Search for publishers, optionally filtering the search against the average
rating of all their books.
"""
queryset = Publisher.objects.annotate(avg_rating=Avg('book__rating'))

queryset = Publisher.objects.annotate(avg_rating=Avg("book__rating"))
serializer_class = PublisherSerializer
filter_backends = [filters.SearchFilter]
search_fields = ['avg_rating']
search_fields = ["avg_rating"]
```

---

## Deprecations

### `serializers.NullBooleanField`

`serializers.NullBooleanField` is now pending deprecation, and will be removed in 3.14.

Instead use `serializers.BooleanField` field and set `allow_null=True` which does the same thing.

---

## Funding

REST framework is a *collaboratively funded project*. If you use
14 changes: 12 additions & 2 deletions docs/community/3.14-announcement.md
Original file line number Diff line number Diff line change
@@ -28,10 +28,10 @@ Our requirements are now:
* Python 3.6+
* Django 4.1, 4.0, 3.2, 3.1, 3.0

## `raise_exceptions` argument for `is_valid` is now keyword-only.
## `raise_exception` argument for `is_valid` is now keyword-only.

Calling `serializer_instance.is_valid(True)` is no longer acceptable syntax.
If you'd like to use the `raise_exceptions` argument, you must use it as a
If you'd like to use the `raise_exception` argument, you must use it as a
keyword argument.

See Pull Request [#7952](https://github.com/encode/django-rest-framework/pull/7952) for more details.
@@ -60,3 +60,13 @@ See Pull Request [#7522](https://github.com/encode/django-rest-framework/pull/75
## Minor fixes and improvements

There are a number of minor fixes and improvements in this release. See the [release notes](release-notes.md) page for a complete listing.

---

## Deprecations

### `serializers.NullBooleanField`

`serializers.NullBooleanField` was moved to pending deprecation in 3.12, and deprecated in 3.13. It has now been removed from the core framework.

Instead use `serializers.BooleanField` field and set `allow_null=True` which does the same thing.
50 changes: 50 additions & 0 deletions docs/community/3.15-announcement.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<style>
.promo li a {
float: left;
width: 130px;
height: 20px;
text-align: center;
margin: 10px 30px;
padding: 150px 0 0 0;
background-position: 0 50%;
background-size: 130px auto;
background-repeat: no-repeat;
font-size: 120%;
color: black;
}
.promo li {
list-style: none;
}
</style>

# Django REST framework 3.15

At the Internet, on March 15th, 2024, with 176 commits by 138 authors, we are happy to announce the release of Django REST framework 3.15.

## Django 5.0 and Python 3.12 support

The latest release now fully supports Django 5.0 and Python 3.12.

The current minimum versions of Django still is 3.0 and Python 3.6.

## Primary Support of UniqueConstraint

`ModelSerializer` generates validators for [UniqueConstraint](https://docs.djangoproject.com/en/4.0/ref/models/constraints/#uniqueconstraint) (both UniqueValidator and UniqueTogetherValidator)

## SimpleRouter non-regex matching support

By default the URLs created by `SimpleRouter` use regular expressions. This behavior can be modified by setting the `use_regex_path` argument to `False` when instantiating the router.

## ZoneInfo as the primary source of timezone data

Dependency on pytz has been removed and deprecation warnings have been added, Django will provide ZoneInfo instances as long as USE_DEPRECATED_PYTZ is not enabled. More info on the migration can be found [in this guide](https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html).

## Align `SearchFilter` behaviour to `django.contrib.admin` search

Searches now may contain _quoted phrases_ with spaces, each phrase is considered as a single search term, and it will raise a validation error if any null-character is provided in search. See the [Filtering API guide](../api-guide/filtering.md) for more information.

## Other fixes and improvements

There are a number of fixes and minor improvements in this release, ranging from documentation, internal infrastructure (typing, testing, requirements, deprecation, etc.), security and overall behaviour.

See the [release notes](release-notes.md) page for a complete listing.
2 changes: 1 addition & 1 deletion docs/community/3.2-announcement.md
Original file line number Diff line number Diff line change
@@ -64,7 +64,7 @@ These are a little subtle and probably won't affect most users, but are worth un

### ManyToMany fields and blank=True

We've now added an `allow_empty` argument, which can be used with `ListSerializer`, or with `many=True` relationships. This is `True` by default, but can be set to `False` if you want to disallow empty lists as valid input.
We've now added an `allow_empty` argument, which can be used with `ListSerializer`, or with `many=True` relationships. This is `True` by default, but can be set to `False` if you want to disallow empty lists as valid input.

As a follow-up to this we are now able to properly mirror the behavior of Django's `ModelForm` with respect to how many-to-many fields are validated.

2 changes: 1 addition & 1 deletion docs/community/3.3-announcement.md
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ The AJAX based support for the browsable API means that there are a number of in

* To support form based `PUT` and `DELETE`, or to support form content types such as JSON, you should now use the [AJAX forms][ajax-form] javascript library. This replaces the previous 'method and content type overloading' that required significant internal complexity to the request class.
* The `accept` query parameter is no longer supported by the default content negotiation class. If you require it then you'll need to [use a custom content negotiation class][accept-headers].
* The custom `HTTP_X_HTTP_METHOD_OVERRIDE` header is no longer supported by default. If you require it then you'll need to [use custom middleware][method-override].
* The custom `HTTP_X_HTTP_METHOD_OVERRIDE` header is no longer supported by default. If you require it then you'll need to [use custom middleware][method-override].

The following pagination view attributes and settings have been moved into attributes on the pagination class since 3.1. Their usage was formerly deprecated, and has now been removed entirely, in line with the deprecation policy.

4 changes: 2 additions & 2 deletions docs/community/3.4-announcement.md
Original file line number Diff line number Diff line change
@@ -89,7 +89,7 @@ Name | Support | PyPI pa
---------------------------------|-------------------------------------|--------------------------------
[Core JSON][core-json] | Schema generation & client support. | Built-in support in `coreapi`.
[Swagger / OpenAPI][swagger] | Schema generation & client support. | The `openapi-codec` package.
[JSON Hyper-Schema][hyperschema] | Currently client support only. | The `hyperschema-codec` package.
[JSON Hyper-Schema][hyperschema] | Currently client support only. | The `hyperschema-codec` package.
[API Blueprint][api-blueprint] | Not yet available. | Not yet available.

---
@@ -187,7 +187,7 @@ The full set of itemized release notes [are available here][release-notes].
[api-blueprint]: https://apiblueprint.org/
[tut-7]: ../tutorial/7-schemas-and-client-libraries/
[schema-generation]: ../api-guide/schemas/
[api-clients]: ../topics/api-clients.md
[api-clients]: https://github.com/encode/django-rest-framework/blob/3.14.0/docs/topics/api-clients.md
[milestone]: https://github.com/encode/django-rest-framework/milestone/35
[release-notes]: release-notes#34
[metadata]: ../api-guide/metadata/#custom-metadata-classes
8 changes: 2 additions & 6 deletions docs/community/3.5-announcement.md
Original file line number Diff line number Diff line change
@@ -64,14 +64,10 @@ from rest_framework.schemas import get_schema_view
from rest_framework_swagger.renderers import OpenAPIRenderer, SwaggerUIRenderer

schema_view = get_schema_view(
title='Example API',
renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer]
title="Example API", renderer_classes=[OpenAPIRenderer, SwaggerUIRenderer]
)

urlpatterns = [
path('swagger/', schema_view),
...
]
urlpatterns = [path("swagger/", schema_view), ...]
```

There have been a large number of fixes to the schema generation. These should
4 changes: 2 additions & 2 deletions docs/community/3.6-announcement.md
Original file line number Diff line number Diff line change
@@ -195,5 +195,5 @@ on realtime support, for the 3.7 release.
[sponsors]: https://fund.django-rest-framework.org/topics/funding/#our-sponsors
[funding]: funding.md
[api-docs]: ../topics/documenting-your-api.md
[js-docs]: ../topics/api-clients.md#javascript-client-library
[py-docs]: ../topics/api-clients.md#python-client-library
[js-docs]: https://github.com/encode/django-rest-framework/blob/3.14.0/docs/topics/api-clients.md#javascript-client-library
[py-docs]: https://github.com/encode/django-rest-framework/blob/3.14.0/docs/topics/api-clients.md#python-client-library
2 changes: 1 addition & 1 deletion docs/community/3.8-announcement.md
Original file line number Diff line number Diff line change
@@ -89,7 +89,7 @@ for a complete listing.

We're currently working towards moving to using [OpenAPI][openapi] as our default schema output. We'll also be revisiting our API documentation generation and client libraries.

We're doing some consolidation in order to make this happen. It's planned that 3.9 will drop the `coreapi` and `coreschema` libraries, and instead use `apistar` for the API documentation generation, schema generation, and API client libraries.
We're doing some consolidation in order to make this happen. It's planned that 3.9 will drop the `coreapi` and `coreschema` libraries, and instead use `apistar` for the API documentation generation, schema generation, and API client libraries.

[funding]: funding.md
[gh5886]: https://github.com/encode/django-rest-framework/issues/5886
11 changes: 4 additions & 7 deletions docs/community/3.9-announcement.md
Original file line number Diff line number Diff line change
@@ -65,15 +65,12 @@ from rest_framework.renderers import JSONOpenAPIRenderer
from django.urls import path

schema_view = get_schema_view(
title='Server Monitoring API',
url='https://www.example.org/api/',
renderer_classes=[JSONOpenAPIRenderer]
title="Server Monitoring API",
url="https://www.example.org/api/",
renderer_classes=[JSONOpenAPIRenderer],
)

urlpatterns = [
path('schema.json', schema_view),
...
]
urlpatterns = [path("schema.json", schema_view), ...]
```

And here's how you can use the `generateschema` management command:
17 changes: 7 additions & 10 deletions docs/community/contributing.md
Original file line number Diff line number Diff line change
@@ -6,11 +6,9 @@
There are many ways you can contribute to Django REST framework. We'd like it to be a community-led project, so please get involved and help shape the future of the project.

---
!!! note

**Note**: At this point in it's lifespan we consider Django REST framework to be essentially feature-complete. We may accept pull requests that track the continued development of Django versions, but would prefer not to accept new features or code formatting changes.

---
At this point in its lifespan we consider Django REST framework to be feature-complete. We focus on pull requests that track the continued development of Django versions, and generally do not accept new features or code formatting changes.

## Community

@@ -36,10 +34,9 @@ Our contribution process is that the [GitHub discussions page](https://github.co

Some tips on good potential issue reporting:

* When describing issues try to phrase your ticket in terms of the *behavior* you think needs changing rather than the *code* you think need changing.
* Django REST framework is considered feature-complete. Please do not file requests to change behavior, unless it is required for security reasons or to maintain compatibility with upcoming Django or Python versions.
* Search the GitHub project page for related items, and make sure you're running the latest version of REST framework before reporting an issue.
* Feature requests will often be closed with a recommendation that they be implemented outside of the core REST framework library. Keeping new feature requests implemented as third party libraries allows us to keep down the maintenance overhead of REST framework, so that the focus can be on continued stability, bugfixes, and great documentation. At this point in it's lifespan we consider Django REST framework to be essentially feature-complete.
* Closing an issue doesn't necessarily mean the end of a discussion. If you believe your issue has been closed incorrectly, explain why and we'll consider if it needs to be reopened.
* Feature requests will typically be closed with a recommendation that they be implemented outside the core REST framework library (e.g. as third-party libraries). This approach allows us to keep down the maintenance overhead of REST framework, so that the focus can be on continued stability and great documentation.

## Triaging issues

@@ -48,8 +45,8 @@ Getting involved in triaging incoming issues is a good way to start contributing
* Read through the ticket - does it make sense, is it missing any context that would help explain it better?
* Is the ticket reported in the correct place, would it be better suited as a discussion on the discussion group?
* If the ticket is a bug report, can you reproduce it? Are you able to write a failing test case that demonstrates the issue and that can be submitted as a pull request?
* If the ticket is a feature request, do you agree with it, and could the feature request instead be implemented as a third party package?
* If a ticket hasn't had much activity and it addresses something you need, then comment on the ticket and try to find out what's needed to get it moving again.
* If the ticket is a feature request, could the feature request instead be implemented as a third party package?
* If a ticket hasn't had much activity and addresses something you need, then comment on the ticket and try to find out what's needed to get it moving again.

# Development

@@ -80,7 +77,7 @@ To run the tests, clone the repository, and then:
# Setup the virtual environment
python3 -m venv env
source env/bin/activate
pip install django
pip install -e .
pip install -r requirements.txt

# Run the tests
796 changes: 398 additions & 398 deletions docs/community/funding.md

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions docs/community/jobs.md
Original file line number Diff line number Diff line change
@@ -14,8 +14,9 @@ Looking for a new Django REST Framework related role? On this site we provide a
* [https://stackoverflow.com/jobs/companies?tl=django][stackoverflow-com]
* [https://www.upwork.com/o/jobs/browse/skill/django-framework/][upwork-com]
* [https://www.technojobs.co.uk/django-jobs][technobjobs-co-uk]
* [https://remoteok.io/remote-django-jobs][remoteok-io]
* [https://remoteok.com/remote-django-jobs][remoteok-com]
* [https://www.remotepython.com/jobs/][remotepython-com]
* [https://www.pyjobs.com/][pyjobs-com]


Know of any other great resources for Django REST Framework jobs that are missing in our list? Please [submit a pull request][submit-pr] or [email us][anna-email].
@@ -32,8 +33,9 @@ Wonder how else you can help? One of the best ways you can help Django REST Fram
[stackoverflow-com]: https://stackoverflow.com/jobs/companies?tl=django
[upwork-com]: https://www.upwork.com/o/jobs/browse/skill/django-framework/
[technobjobs-co-uk]: https://www.technojobs.co.uk/django-jobs
[remoteok-io]: https://remoteok.io/remote-django-jobs
[remoteok-com]: https://remoteok.com/remote-django-jobs
[remotepython-com]: https://www.remotepython.com/jobs/
[pyjobs-com]: https://www.pyjobs.com/
[drf-funding]: https://fund.django-rest-framework.org/topics/funding/
[submit-pr]: https://github.com/encode/django-rest-framework
[anna-email]: mailto:anna@django-rest-framework.org
65 changes: 10 additions & 55 deletions docs/community/project-management.md
Original file line number Diff line number Diff line change
@@ -13,55 +13,13 @@ The aim is to ensure that the project has a high

## Maintenance team

We have a quarterly maintenance cycle where new members may join the maintenance team. We currently cap the size of the team at 5 members, and may encourage folks to step out of the team for a cycle to allow new members to participate.
[Participating actively in the REST framework project](contributing.md) **does not require being part of the maintenance team**. Almost every important part of issue triage and project improvement can be actively worked on regardless of your collaborator status on the repository.

#### Current team
#### Composition

The [maintenance team for Q4 2015](https://github.com/encode/django-rest-framework/issues/2190):
The composition of the maintenance team is handled by [@tomchristie](https://github.com/encode/). Team members will be added as collaborators to the repository.

* [@tomchristie](https://github.com/encode/)
* [@xordoquy](https://github.com/xordoquy/) (Release manager.)
* [@carltongibson](https://github.com/carltongibson/)
* [@kevin-brown](https://github.com/kevin-brown/)
* [@jpadilla](https://github.com/jpadilla/)

#### Maintenance cycles

Each maintenance cycle is initiated by an issue being opened with the `Process` label.

* To be considered for a maintainer role simply comment against the issue.
* Existing members must explicitly opt-in to the next cycle by check-marking their name.
* The final decision on the incoming team will be made by `@tomchristie`.

Members of the maintenance team will be added as collaborators to the repository.

The following template should be used for the description of the issue, and serves as the formal process for selecting the team.

This issue is for determining the maintenance team for the *** period.

Please see the [Project management](https://www.django-rest-framework.org/topics/project-management/) section of our documentation for more details.

---

#### Renewing existing members.

The following people are the current maintenance team. Please checkmark your name if you wish to continue to have write permission on the repository for the *** period.

- [ ] @***
- [ ] @***
- [ ] @***
- [ ] @***
- [ ] @***

---

#### New members.

If you wish to be considered for this or a future date, please comment against this or subsequent issues.

To modify this process for future maintenance cycles make a pull request to the [project management](https://www.django-rest-framework.org/topics/project-management/) documentation.

#### Responsibilities of team members
#### Responsibilities

Team members have the following responsibilities.

@@ -78,16 +36,12 @@ Further notes for maintainers:
* Each issue/pull request should have exactly one label once triaged.
* Search for un-triaged issues with [is:open no:label][un-triaged].

It should be noted that participating actively in the REST framework project clearly **does not require being part of the maintenance team**. Almost every import part of issue triage and project improvement can be actively worked on regardless of your collaborator status on the repository.

---

## Release process

The release manager is selected on every quarterly maintenance cycle.

* The manager should be selected by `@tomchristie`.
* The manager will then have the maintainer role added to PyPI package.
* The release manager is selected by `@tomchristie`.
* The release manager will then have the maintainer role added to PyPI package.
* The previous manager will then have the maintainer role removed from the PyPI package.

Our PyPI releases will be handled by either the current release manager, or by `@tomchristie`. Every release should have an open issue tagged with the `Release` label and marked against the appropriate milestone.
@@ -112,6 +66,9 @@ The following template should be used for the description of the issue, and serv
- [ ] `docs` Python & Django versions
- [ ] Update the translations from [transifex](https://www.django-rest-framework.org/topics/project-management/#translations).
- [ ] Ensure the pull request increments the version to `*.*.*` in [`restframework/__init__.py`](https://github.com/encode/django-rest-framework/blob/master/rest_framework/__init__.py).
- [ ] Ensure documentation validates
- Build and serve docs `mkdocs serve`
- Validate links `pylinkvalidate.py -P http://127.0.0.1:8000`
- [ ] Confirm with @tomchristie that release is finalized and ready to go.
- [ ] Ensure that release date is included in pull request.
- [ ] Merge the release pull request.
@@ -195,8 +152,7 @@ If `@tomchristie` ceases to participate in the project then `@j4mie` has respons

The following issues still need to be addressed:

* Ensure `@jamie` has back-up access to the `django-rest-framework.org` domain setup and admin.
* Document ownership of the [live example][sandbox] API.
* Ensure `@j4mie` has back-up access to the `django-rest-framework.org` domain setup and admin.
* Document ownership of the [mailing list][mailing-list] and IRC channel.
* Document ownership and management of the security mailing list.

@@ -205,5 +161,4 @@ The following issues still need to be addressed:
[transifex-project]: https://www.transifex.com/projects/p/django-rest-framework/
[transifex-client]: https://pypi.org/project/transifex-client/
[translation-memory]: http://docs.transifex.com/guides/tm#let-tm-automatically-populate-translations
[sandbox]: https://restframework.herokuapp.com/
[mailing-list]: https://groups.google.com/forum/#!forum/django-rest-framework
123 changes: 115 additions & 8 deletions docs/community/release-notes.md

Large diffs are not rendered by default.

17 changes: 14 additions & 3 deletions docs/community/third-party-packages.md
Original file line number Diff line number Diff line change
@@ -121,10 +121,11 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
* [djangorestframework-chain][djangorestframework-chain] - Allows arbitrary chaining of both relations and lookup filters.
* [django-url-filter][django-url-filter] - Allows a safe way to filter data via human-friendly URLs. It is a generic library which is not tied to DRF but it provides easy integration with DRF.
* [drf-url-filter][drf-url-filter] is a simple Django app to apply filters on drf `ModelViewSet`'s `Queryset` in a clean, simple and configurable way. It also supports validations on incoming query params and their values.
* [django-rest-framework-guardian][django-rest-framework-guardian] - Provides integration with django-guardian, including the `DjangoObjectPermissionsFilter` previously found in DRF.
* [django-rest-framework-guardian2][django-rest-framework-guardian2] - Provides integration with django-guardian, including the `DjangoObjectPermissionsFilter` previously found in DRF.

### Misc

* [drf-sendables][drf-sendables] - User messages for Django REST Framework
* [cookiecutter-django-rest][cookiecutter-django-rest] - A cookiecutter template that takes care of the setup and configuration so you can focus on making your REST apis awesome.
* [djangorestrelationalhyperlink][djangorestrelationalhyperlink] - A hyperlinked serializer that can can be used to alter relationships via hyperlinks, but otherwise like a hyperlink model serializer.
* [django-rest-framework-proxy][django-rest-framework-proxy] - Proxy to redirect incoming request to another API server.
@@ -150,7 +151,14 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
* [fast-drf] - A model based library for making API development faster and easier.
* [django-requestlogs] - Providing middleware and other helpers for audit logging for REST framework.
* [drf-standardized-errors][drf-standardized-errors] - DRF exception handler to standardize error responses for all API endpoints.
* [drf-api-action][drf-api-action] - uses the power of DRF also as a library functions

### Customization

* [drf-redesign][drf-redesign] - A project that gives a fresh look to the browse-able API using Bootstrap 5.
* [drf-material][drf-material] - A project that gives a sleek and elegant look to the browsable API using Material Design.

[drf-sendables]: https://github.com/amikrop/drf-sendables
[cite]: http://www.software-ecosystems.com/Software_Ecosystems/Ecosystems.html
[cookiecutter]: https://github.com/jpadilla/cookiecutter-django-rest-framework
[new-repo]: https://github.com/new
@@ -205,7 +213,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
[dry-rest-permissions]: https://github.com/FJNR-inc/dry-rest-permissions
[django-url-filter]: https://github.com/miki725/django-url-filter
[drf-url-filter]: https://github.com/manjitkumar/drf-url-filters
[cookiecutter-django-rest]: https://github.com/agconti/cookiecutter-django-rest
[cookiecutter-django-rest]: https://github.com/agconti/cookiecutter-django-rest
[drf-haystack]: https://drf-haystack.readthedocs.io/en/latest/
[django-rest-framework-version-transforms]: https://github.com/mrhwick/django-rest-framework-version-transforms
[djangorestframework-jsonapi]: https://github.com/django-json-api/django-rest-framework-json-api
@@ -229,7 +237,7 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
[djangorestframework-dataclasses]: https://github.com/oxan/djangorestframework-dataclasses
[django-restql]: https://github.com/yezyilomo/django-restql
[djangorestframework-mvt]: https://github.com/corteva/djangorestframework-mvt
[django-rest-framework-guardian]: https://github.com/rpkilby/django-rest-framework-guardian
[django-rest-framework-guardian2]: https://github.com/johnthagen/django-rest-framework-guardian2
[drf-viewset-profiler]: https://github.com/fvlima/drf-viewset-profiler
[djangorestframework-features]: https://github.com/cloudcode-hungary/django-rest-framework-features/
[django-elasticsearch-dsl-drf]: https://github.com/barseghyanartur/django-elasticsearch-dsl-drf
@@ -241,3 +249,6 @@ To submit new content, [open an issue][drf-create-issue] or [create a pull reque
[fast-drf]: https://github.com/iashraful/fast-drf
[django-requestlogs]: https://github.com/Raekkeri/django-requestlogs
[drf-standardized-errors]: https://github.com/ghazi-git/drf-standardized-errors
[drf-api-action]: https://github.com/Ori-Roza/drf-api-action
[drf-redesign]: https://github.com/youzarsiph/drf-redesign
[drf-material]: https://github.com/youzarsiph/drf-material
5 changes: 5 additions & 0 deletions docs/community/tutorials-and-resources.md
Original file line number Diff line number Diff line change
@@ -19,6 +19,10 @@ There are a wide range of resources available for learning and using Django REST
</a>
</div>

## Courses

* [Developing RESTful APIs with Django REST Framework][developing-restful-apis-with-django-rest-framework]

## Tutorials

* [Beginner's Guide to the Django REST Framework][beginners-guide-to-the-django-rest-framework]
@@ -130,3 +134,4 @@ Want your Django REST Framework talk/tutorial/article to be added to our website
[pycon-us-2017]: https://www.youtube.com/watch?v=Rk6MHZdust4
[django-rest-react-valentinog]: https://www.valentinog.com/blog/tutorial-api-django-rest-react/
[doordash-implementing-rest-apis]: https://doordash.engineering/2013/10/07/implementing-rest-apis-with-embedded-privacy/
[developing-restful-apis-with-django-rest-framework]: https://testdriven.io/courses/django-rest-framework/
242 changes: 0 additions & 242 deletions docs/coreapi/7-schemas-and-client-libraries.md

This file was deleted.

Loading