commonground-api-common 2.5.5__tar.gz → 2.6.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/CHANGELOG.rst +18 -0
  2. {commonground_api_common-2.5.5/commonground_api_common.egg-info → commonground_api_common-2.6.1}/PKG-INFO +1 -2
  3. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1/commonground_api_common.egg-info}/PKG-INFO +1 -2
  4. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/commonground_api_common.egg-info/SOURCES.txt +2 -0
  5. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/commonground_api_common.egg-info/requires.txt +0 -1
  6. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/setup.cfg +1 -2
  7. commonground_api_common-2.6.1/tests/test_cached_hyperlinkrelatedfields.py +127 -0
  8. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_gegevensgroepen.py +7 -1
  9. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_nested_serializer_validation.py +4 -4
  10. commonground_api_common-2.6.1/tests/test_serializer_fields.py +58 -0
  11. commonground_api_common-2.6.1/vng_api_common/__init__.py +1 -0
  12. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/utils.py +1 -0
  13. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/serializers.py +126 -28
  14. commonground_api_common-2.5.5/vng_api_common/__init__.py +0 -1
  15. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/MANIFEST.in +0 -0
  16. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/README.rst +0 -0
  17. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/bin/generate_schema +0 -0
  18. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/commonground_api_common.egg-info/dependency_links.txt +0 -0
  19. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/commonground_api_common.egg-info/not-zip-safe +0 -0
  20. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/commonground_api_common.egg-info/top_level.txt +0 -0
  21. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/pyproject.toml +0 -0
  22. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/setup.py +0 -0
  23. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_autorisatie_validation.py +0 -0
  24. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_cache_headers.py +0 -0
  25. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_check_query_params.py +0 -0
  26. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_checks.py +0 -0
  27. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_choices.py +0 -0
  28. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_configuration_steps_applicaties.py +0 -0
  29. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_configuration_steps_jwtsecrets.py +0 -0
  30. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_content_type_headers.py +0 -0
  31. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_field_extensions.py +0 -0
  32. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_filter_extension.py +0 -0
  33. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_filters.py +0 -0
  34. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_get_resource.py +0 -0
  35. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_jwt_decoding.py +0 -0
  36. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_jwtsecrets.py +0 -0
  37. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_migrations.py +0 -0
  38. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_pagination.py +0 -0
  39. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_permissions.py +0 -0
  40. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_publish_validators.py +0 -0
  41. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_schema.py +0 -0
  42. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_serializer_extensions.py +0 -0
  43. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_server_errors.py +0 -0
  44. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_utils.py +0 -0
  45. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_validators.py +0 -0
  46. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/tests/test_views.py +0 -0
  47. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/admin.py +0 -0
  48. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/api/__init__.py +0 -0
  49. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/api/permissions.py +0 -0
  50. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/api/serializers.py +0 -0
  51. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/api/urls.py +0 -0
  52. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/api/views.py +0 -0
  53. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/apps.py +0 -0
  54. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/__init__.py +0 -0
  55. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/admin.py +0 -0
  56. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/api/__init__.py +0 -0
  57. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/api/scopes.py +0 -0
  58. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/api/serializers.py +0 -0
  59. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/apps.py +0 -0
  60. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/audits.py +0 -0
  61. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0001_initial.py +0 -0
  62. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0002_auto_20190516_0830.py +0 -0
  63. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0003_auto_20190517_0844.py +0 -0
  64. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0004_auto_20190520_1238.py +0 -0
  65. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0005_auto_20190520_1450.py +0 -0
  66. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0006_audittrail_toelichting.py +0 -0
  67. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0007_auto_20190522_0916.py +0 -0
  68. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0008_audittrail_resource_weergave.py +0 -0
  69. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0009_auto_20190712_1643.py +0 -0
  70. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0010_audittrail_request_id.py +0 -0
  71. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0011_auto_20190918_1335.py +0 -0
  72. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0012_auto_20200619_0545.py +0 -0
  73. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0012_remove_audittrail_request_id.py +0 -0
  74. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0013_audittrail_logrecord_id.py +0 -0
  75. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0013_auto_20201207_0846.py +0 -0
  76. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0014_auto_20201221_0905.py +0 -0
  77. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0014_auto_20210323_1654.py +0 -0
  78. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0015_auto_20220318_1608.py +0 -0
  79. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0016_merge_20220607_0517.py +0 -0
  80. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0017_alter_audittrail_bron.py +0 -0
  81. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/0018_auto_20221212_0745.py +0 -0
  82. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/__init__.py +0 -0
  83. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/migrations/_operations.py +0 -0
  84. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/models.py +0 -0
  85. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/utils.py +0 -0
  86. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/audittrails/viewsets.py +0 -0
  87. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/__init__.py +0 -0
  88. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/admin.py +0 -0
  89. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/middleware.py +0 -0
  90. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0001_initial.py +0 -0
  91. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0002_authorizationsconfig.py +0 -0
  92. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0003_auto_20190502_0409.py +0 -0
  93. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0004_auto_20190503_0941.py +0 -0
  94. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0005_auto_20190506_0842.py +0 -0
  95. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0006_auto_20190506_0901.py +0 -0
  96. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0007_auto_20190506_1212.py +0 -0
  97. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0008_auto_20190712_1541.py +0 -0
  98. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0009_update_enums.py +0 -0
  99. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0010_auto_20190712_1643.py +0 -0
  100. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0011_auto_20191114_0728.py +0 -0
  101. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0012_auto_20200619_0545.py +0 -0
  102. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0013_auto_20201207_0846.py +0 -0
  103. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0014_auto_20201221_0905.py +0 -0
  104. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0015_auto_20220318_1608.py +0 -0
  105. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0016_remove_authorizationsconfig_api_root_and_more.py +0 -0
  106. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/0017_alter_applicatie_client_ids_and_more.py +0 -0
  107. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/migrations/__init__.py +0 -0
  108. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/models.py +0 -0
  109. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/serializers.py +0 -0
  110. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/authorizations/validators.py +0 -0
  111. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/caching/__init__.py +0 -0
  112. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/caching/decorators.py +0 -0
  113. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/caching/etags.py +0 -0
  114. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/caching/introspection.py +0 -0
  115. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/caching/models.py +0 -0
  116. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/caching/registry.py +0 -0
  117. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/caching/signals.py +0 -0
  118. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/checks.py +0 -0
  119. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/choices.py +0 -0
  120. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/client.py +0 -0
  121. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/compat.py +0 -0
  122. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/conf/__init__.py +0 -0
  123. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/conf/api.py +0 -0
  124. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/constants.py +0 -0
  125. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/contrib/__init__.py +0 -0
  126. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/contrib/setup_configuration/__init__.py +0 -0
  127. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/contrib/setup_configuration/models.py +0 -0
  128. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/contrib/setup_configuration/steps.py +0 -0
  129. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/db/__init__.py +0 -0
  130. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/db/operations.py +0 -0
  131. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/decorators.py +0 -0
  132. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/descriptors.py +0 -0
  133. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/doc.py +0 -0
  134. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/exception_handling.py +0 -0
  135. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/exceptions.py +0 -0
  136. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/extensions/__init__.py +0 -0
  137. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/extensions/file.py +0 -0
  138. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/extensions/gegevensgroep.py +0 -0
  139. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/extensions/geojson.py +0 -0
  140. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/extensions/hyperlink.py +0 -0
  141. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/extensions/polymorphic.py +0 -0
  142. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/extensions/query.py +0 -0
  143. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/fields.py +0 -0
  144. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/filters.py +0 -0
  145. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/filtersets.py +0 -0
  146. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/generators.py +0 -0
  147. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/geo.py +0 -0
  148. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/locale/nl/LC_MESSAGES/django.mo +0 -0
  149. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/locale/nl/LC_MESSAGES/django.po +0 -0
  150. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/middleware.py +0 -0
  151. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/migrations/0001_initial.py +0 -0
  152. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/migrations/0002_apicredential.py +0 -0
  153. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/migrations/0003_auto_20190417_1145.py +0 -0
  154. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/migrations/0004_auto_20190517_0903.py +0 -0
  155. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/migrations/0005_auto_20190614_1346.py +0 -0
  156. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/migrations/0006_delete_apicredential.py +0 -0
  157. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/migrations/__init__.py +0 -0
  158. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/mocks.py +0 -0
  159. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/models.py +0 -0
  160. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/__init__.py +0 -0
  161. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/api/__init__.py +0 -0
  162. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/api/urls.py +0 -0
  163. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/api/views.py +0 -0
  164. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/apps.py +0 -0
  165. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/handlers.py +0 -0
  166. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0001_initial.py +0 -0
  167. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0002_subscription__subscription.py +0 -0
  168. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0003_auto_20190319_1048.py +0 -0
  169. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0004_auto_20190325_1313.py +0 -0
  170. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0005_fix_default_nrc.py +0 -0
  171. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0006_auto_20190417_1142.py +0 -0
  172. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0007_auto_20190429_1442.py +0 -0
  173. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0008_auto_20190502_0415.py +0 -0
  174. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0009_auto_20190729_0427.py +0 -0
  175. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0010_auto_20220704_1419.py +0 -0
  176. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/0011_remove_subscription_config_and_more.py +0 -0
  177. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/notifications/migrations/__init__.py +0 -0
  178. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/oas.py +0 -0
  179. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/pagination.py +0 -0
  180. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/permissions.py +0 -0
  181. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/polymorphism.py +0 -0
  182. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/routers.py +0 -0
  183. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/schema.py +0 -0
  184. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/scopes.py +0 -0
  185. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/search.py +0 -0
  186. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/css/admin/admin_overrides.css +0 -0
  187. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/css/screen.css +0 -0
  188. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/ico/favicon.png +0 -0
  189. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/img/vng.svg +0 -0
  190. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/LICENSE.txt +0 -0
  191. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/css/all.css +0 -0
  192. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/css/all.min.css +0 -0
  193. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-brands-400.eot +0 -0
  194. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-brands-400.svg +0 -0
  195. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-brands-400.ttf +0 -0
  196. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-brands-400.woff +0 -0
  197. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-brands-400.woff2 +0 -0
  198. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-regular-400.eot +0 -0
  199. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-regular-400.svg +0 -0
  200. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-regular-400.ttf +0 -0
  201. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-regular-400.woff +0 -0
  202. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-regular-400.woff2 +0 -0
  203. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-solid-900.eot +0 -0
  204. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-solid-900.svg +0 -0
  205. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-solid-900.ttf +0 -0
  206. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-solid-900.woff +0 -0
  207. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/static/vng_api_common/libs/fontawesome/webfonts/fa-solid-900.woff2 +0 -0
  208. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/templates/vng_api_common/admin/base_site.html +0 -0
  209. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/templates/vng_api_common/includes/kanalen_card.html +0 -0
  210. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/templates/vng_api_common/index.html +0 -0
  211. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/templates/vng_api_common/master.html +0 -0
  212. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/templates/vng_api_common/ref/error_detail.html +0 -0
  213. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/templates/vng_api_common/ref/scopes.html +0 -0
  214. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/templates/vng_api_common/view_config.html +0 -0
  215. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/templatetags/__init__.py +0 -0
  216. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/templatetags/vng_api_common.py +0 -0
  217. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/tests/__init__.py +0 -0
  218. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/tests/auth.py +0 -0
  219. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/tests/caching.py +0 -0
  220. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/tests/schema.py +0 -0
  221. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/tests/urls.py +0 -0
  222. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/urls.py +0 -0
  223. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/utils.py +0 -0
  224. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/validators.py +0 -0
  225. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/version.py +0 -0
  226. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/views.py +0 -0
  227. {commonground_api_common-2.5.5 → commonground_api_common-2.6.1}/vng_api_common/viewsets.py +0 -0
@@ -2,6 +2,24 @@
2
2
  Change history
3
3
  ==============
4
4
 
5
+ 2.6.1 (2025-04-14)
6
+ ------------------
7
+
8
+ * [open-zaak/open-zaak#1799] Fix ``DurationField`` to consistently support negative durations.
9
+
10
+ 2.6.0 (2025-04-07)
11
+ ------------------
12
+
13
+ **New features**
14
+
15
+ * [open-zaak/open-zaak#1970] Add several DRF hyperlinked field classes that cache the results of ``reverse()`` to
16
+ avoid running the same logic multiple times. This can improve performance for serialization
17
+ with hyperlinked fields by quite a bit, especially for list operations
18
+
19
+ * ``vng_api_common.serializers.CachedHyperlinkedIdentityField``
20
+ * ``vng_api_common.serializers.CachedHyperlinkedRelatedField``
21
+ * ``vng_api_common.serializers.CachedNestedHyperlinkedRelatedField``
22
+
5
23
  2.5.5 (2025-03-21)
6
24
  ------------------
7
25
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commonground-api-common
3
- Version: 2.5.5
3
+ Version: 2.6.1
4
4
  Summary: Commonground API tooling
5
5
  Home-page: https://github.com/maykinmedia/commonground-api-common
6
6
  Author: Maykin Media, VNG-Realisatie
@@ -28,7 +28,6 @@ Requires-Dist: django-rest-framework-condition
28
28
  Requires-Dist: drf-nested-routers>=0.94.1
29
29
  Requires-Dist: drf-spectacular
30
30
  Requires-Dist: iso-639
31
- Requires-Dist: isodate
32
31
  Requires-Dist: notifications-api-common>=0.3.1
33
32
  Requires-Dist: zgw-consumers>=0.35.1
34
33
  Requires-Dist: oyaml
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: commonground-api-common
3
- Version: 2.5.5
3
+ Version: 2.6.1
4
4
  Summary: Commonground API tooling
5
5
  Home-page: https://github.com/maykinmedia/commonground-api-common
6
6
  Author: Maykin Media, VNG-Realisatie
@@ -28,7 +28,6 @@ Requires-Dist: django-rest-framework-condition
28
28
  Requires-Dist: drf-nested-routers>=0.94.1
29
29
  Requires-Dist: drf-spectacular
30
30
  Requires-Dist: iso-639
31
- Requires-Dist: isodate
32
31
  Requires-Dist: notifications-api-common>=0.3.1
33
32
  Requires-Dist: zgw-consumers>=0.35.1
34
33
  Requires-Dist: oyaml
@@ -13,6 +13,7 @@ commonground_api_common.egg-info/requires.txt
13
13
  commonground_api_common.egg-info/top_level.txt
14
14
  tests/test_autorisatie_validation.py
15
15
  tests/test_cache_headers.py
16
+ tests/test_cached_hyperlinkrelatedfields.py
16
17
  tests/test_check_query_params.py
17
18
  tests/test_checks.py
18
19
  tests/test_choices.py
@@ -33,6 +34,7 @@ tests/test_permissions.py
33
34
  tests/test_publish_validators.py
34
35
  tests/test_schema.py
35
36
  tests/test_serializer_extensions.py
37
+ tests/test_serializer_fields.py
36
38
  tests/test_server_errors.py
37
39
  tests/test_utils.py
38
40
  tests/test_validators.py
@@ -7,7 +7,6 @@ django-rest-framework-condition
7
7
  drf-nested-routers>=0.94.1
8
8
  drf-spectacular
9
9
  iso-639
10
- isodate
11
10
  notifications-api-common>=0.3.1
12
11
  zgw-consumers>=0.35.1
13
12
  oyaml
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = commonground-api-common
3
- version = 2.5.5
3
+ version = 2.6.1
4
4
  description = Commonground API tooling
5
5
  long_description = file: README.rst
6
6
  url = https://github.com/maykinmedia/commonground-api-common
@@ -38,7 +38,6 @@ install_requires =
38
38
  drf-nested-routers>=0.94.1
39
39
  drf-spectacular
40
40
  iso-639
41
- isodate
42
41
  notifications-api-common>=0.3.1
43
42
  zgw-consumers>=0.35.1
44
43
  oyaml
@@ -0,0 +1,127 @@
1
+ from unittest.mock import patch
2
+
3
+ from django.urls import reverse
4
+
5
+ import pytest
6
+ from rest_framework.reverse import reverse
7
+
8
+ from testapp.factories import GroupFactory, PersonFactory
9
+
10
+
11
+ @pytest.mark.django_db
12
+ def test_cached_hyperlinkedrelatedfield(api_client):
13
+ """
14
+ Caching is applied to the base URI for each view in CachedHyperlinkedRelatedField,
15
+ but this cache must be only be applied within the same requests, to ensure that
16
+ requests with different HTTP_HOSTs show the correct domain in their responses
17
+ """
18
+ group = GroupFactory.create(name="group1")
19
+ person = PersonFactory.create(
20
+ name="John Doe", address_street="Foo", address_number="1", group=group
21
+ )
22
+
23
+ response = api_client.get(reverse("person-detail", kwargs={"pk": person.pk}))
24
+
25
+ expected = {
26
+ "url": f"http://testserver{reverse('person-detail', kwargs={'pk': person.pk})}",
27
+ "address": {"street": "Foo", "number": "1"},
28
+ "name": "John Doe",
29
+ "group_name": "group1",
30
+ "group_url": f"http://testserver{reverse('group-detail', kwargs={'pk': group.pk})}",
31
+ }
32
+
33
+ assert response.data == expected
34
+
35
+ response = api_client.get(
36
+ reverse("person-detail", kwargs={"pk": person.pk}), HTTP_HOST="different.local"
37
+ )
38
+
39
+ expected = {
40
+ "url": f"http://different.local{reverse('person-detail', kwargs={'pk': person.pk})}",
41
+ "address": {"street": "Foo", "number": "1"},
42
+ "name": "John Doe",
43
+ "group_name": "group1",
44
+ "group_url": f"http://different.local{reverse('group-detail', kwargs={'pk': group.pk})}",
45
+ }
46
+
47
+ assert response.data == expected
48
+
49
+
50
+ @pytest.mark.django_db
51
+ def test_cached_nested_hyperlinkedrelatedfield(api_client):
52
+ """
53
+ Caching is applied to the base URI for each view in CachedNestedHyperlinkedRelatedField,
54
+ but this cache must be only be applied within the same requests, to ensure that
55
+ requests with different HTTP_HOSTs show the correct domain in their responses
56
+ """
57
+ group = GroupFactory.create(name="group1")
58
+ person1 = PersonFactory.create(
59
+ name="John Doe", address_street="Foo", address_number="1", group=group
60
+ )
61
+ person2 = PersonFactory.create(
62
+ name="Jane Doe", address_street="Bar", address_number="2", group=group
63
+ )
64
+
65
+ with patch("rest_framework.relations.reverse", side_effect=reverse) as mock_reverse:
66
+ response = api_client.get(reverse("group-detail", kwargs={"pk": group.pk}))
67
+
68
+ # Without caching 6 calls would be made to reverse, caching reduces this to 3
69
+ # (one for each view)
70
+ assert mock_reverse.call_count == 3
71
+ assert mock_reverse.call_args_list[0].args == ("person-detail",)
72
+ assert mock_reverse.call_args_list[1].args == ("group-detail",)
73
+ assert mock_reverse.call_args_list[2].args == ("nested-person-detail",)
74
+
75
+ expected = {
76
+ "persons": [
77
+ {
78
+ "url": f"http://testserver{reverse('person-detail', kwargs={'pk': person1.pk})}",
79
+ "address": {"street": "Foo", "number": "1"},
80
+ "name": "John Doe",
81
+ "group_name": "group1",
82
+ "group_url": f"http://testserver{reverse('group-detail', kwargs={'pk': group.pk})}",
83
+ },
84
+ {
85
+ "url": f"http://testserver{reverse('person-detail', kwargs={'pk': person2.pk})}",
86
+ "address": {"street": "Bar", "number": "2"},
87
+ "name": "Jane Doe",
88
+ "group_name": "group1",
89
+ "group_url": f"http://testserver{reverse('group-detail', kwargs={'pk': group.pk})}",
90
+ },
91
+ ],
92
+ "nested_persons": [
93
+ f"http://testserver{reverse('nested-person-detail', kwargs={'group_pk': group.pk, 'pk': person1.pk})}",
94
+ f"http://testserver{reverse('nested-person-detail', kwargs={'group_pk': group.pk, 'pk': person2.pk})}",
95
+ ],
96
+ }
97
+
98
+ assert response.data == expected
99
+
100
+ response = api_client.get(
101
+ reverse("group-detail", kwargs={"pk": group.pk}), HTTP_HOST="different.local"
102
+ )
103
+
104
+ expected = {
105
+ "persons": [
106
+ {
107
+ "url": f"http://different.local{reverse('person-detail', kwargs={'pk': person1.pk})}",
108
+ "address": {"street": "Foo", "number": "1"},
109
+ "name": "John Doe",
110
+ "group_name": "group1",
111
+ "group_url": f"http://different.local{reverse('group-detail', kwargs={'pk': group.pk})}",
112
+ },
113
+ {
114
+ "url": f"http://different.local{reverse('person-detail', kwargs={'pk': person2.pk})}",
115
+ "address": {"street": "Bar", "number": "2"},
116
+ "name": "Jane Doe",
117
+ "group_name": "group1",
118
+ "group_url": f"http://different.local{reverse('group-detail', kwargs={'pk': group.pk})}",
119
+ },
120
+ ],
121
+ "nested_persons": [
122
+ f"http://different.local{reverse('nested-person-detail', kwargs={'group_pk': group.pk, 'pk': person1.pk})}",
123
+ f"http://different.local{reverse('nested-person-detail', kwargs={'group_pk': group.pk, 'pk': person2.pk})}",
124
+ ],
125
+ }
126
+
127
+ assert response.data == expected
@@ -1,3 +1,5 @@
1
+ from rest_framework.test import APIRequestFactory
2
+
1
3
  from testapp.models import Group, Person
2
4
  from testapp.serializers import PersonSerializer, PersonSerializer2
3
5
 
@@ -93,7 +95,11 @@ def test_assignment_missing_optional_key():
93
95
 
94
96
  def test_nullable_gegevensgroep():
95
97
  person = Person(name="bla", address_street="", address_number="")
96
- output = PersonSerializer().to_representation(instance=person)
98
+ factory = APIRequestFactory()
99
+ request = factory.get("/persons")
100
+ output = PersonSerializer(context={"request": request}).to_representation(
101
+ instance=person
102
+ )
97
103
  assert output["address"] == {
98
104
  "street": "",
99
105
  "number": "",
@@ -43,7 +43,7 @@ def test_create_invalid_params():
43
43
  """
44
44
  serializer = GroupSerializer(
45
45
  data={
46
- "person": [
46
+ "persons": [
47
47
  {
48
48
  "name": "john",
49
49
  "address": {"street": "Keizersgracht", "number": "416"},
@@ -59,17 +59,17 @@ def test_create_invalid_params():
59
59
 
60
60
  validation_errors = list(get_validation_errors(serializer.errors))
61
61
 
62
- assert validation_errors[0]["name"] == "person.1.address.street"
62
+ assert validation_errors[0]["name"] == "persons.1.address.street"
63
63
  assert validation_errors[0]["code"] == "required"
64
64
 
65
- assert validation_errors[1]["name"] == "person.2.name"
65
+ assert validation_errors[1]["name"] == "persons.2.name"
66
66
  assert validation_errors[1]["code"] == "required"
67
67
 
68
68
 
69
69
  def test_create_valid():
70
70
  serializer = GroupSerializer(
71
71
  data={
72
- "person": [
72
+ "persons": [
73
73
  {
74
74
  "name": "test",
75
75
  "address": {"street": "Keizersgracht", "number": "117"},
@@ -0,0 +1,58 @@
1
+ from dateutil.relativedelta import relativedelta
2
+ from rest_framework import serializers, viewsets
3
+
4
+ from vng_api_common.serializers import DurationField
5
+
6
+ VALID_DURATION_OPTIONS = [
7
+ ("P10D", relativedelta(days=10)),
8
+ ("P1M10D", relativedelta(months=1, days=10)),
9
+ ("P1Y1M10D", relativedelta(years=1, months=1, days=10)),
10
+ ("P-10D", relativedelta(days=-10)),
11
+ ("P-1M-10D", relativedelta(months=-1, days=-10)),
12
+ ("P-1Y-1M-10D", relativedelta(years=-1, months=-1, days=-10)),
13
+ ("P1Y-1M10D", relativedelta(years=+1, months=-1, days=+10)),
14
+ ]
15
+
16
+
17
+ class DurationSerializer(serializers.Serializer):
18
+ duration = DurationField()
19
+
20
+
21
+ class DurationView(viewsets.ModelViewSet):
22
+ serializer_class = DurationSerializer
23
+
24
+
25
+ def test_duration_field_valid_serialization():
26
+ data = {"duration": ""}
27
+ for duration in VALID_DURATION_OPTIONS:
28
+ data["duration"] = duration[0]
29
+ serializer = DurationSerializer(data=data)
30
+ assert serializer.is_valid()
31
+ assert serializer.to_representation({"duration": duration[1]}) == data
32
+
33
+
34
+ def test_duration_field_valid_deserialization():
35
+ data = {"duration": ""}
36
+ for duration in VALID_DURATION_OPTIONS:
37
+ data["duration"] = duration[0]
38
+ serializer = DurationSerializer(data=data)
39
+ assert serializer.is_valid()
40
+ assert serializer.to_internal_value(data) == {"duration": duration[1]}
41
+
42
+
43
+ def test_duration_field_invalid_deserialization():
44
+ duration_options = [
45
+ "test",
46
+ "10D",
47
+ "-P10D",
48
+ "-P-10D",
49
+ ]
50
+ data = {"duration": ""}
51
+ for d in duration_options:
52
+ data["duration"] = d
53
+ serializer = DurationSerializer(data=data)
54
+ assert not serializer.is_valid()
55
+ assert (
56
+ serializer.errors["duration"][0]
57
+ == "Duration has wrong format. Use one of these formats instead: P(n)Y(n)M(n)D."
58
+ )
@@ -0,0 +1 @@
1
+ __version__ = "2.6.1"
@@ -12,6 +12,7 @@ def generate_jwt(client_id, secret, user_id, user_representation):
12
12
  secret=secret,
13
13
  user_id=user_id,
14
14
  user_representation=user_representation,
15
+ jwt_valid_for=5 * 60,
15
16
  )
16
17
  )
17
18
  return f"Bearer {auth._token}"
@@ -1,54 +1,45 @@
1
- import datetime
2
1
  import inspect
3
2
  from collections import OrderedDict
3
+ from functools import reduce
4
4
  from typing import List, Optional, Tuple, Union
5
5
 
6
6
  from django.db import models, transaction
7
+ from django.db.models import Model
7
8
  from django.utils.translation import gettext_lazy as _
8
9
 
9
- import isodate
10
+ from dateutil.relativedelta import relativedelta
10
11
  from rest_framework import fields, serializers
12
+ from rest_framework.request import Request
13
+ from rest_framework_nested.relations import NestedHyperlinkedRelatedField
11
14
 
12
15
  from .choices import TextChoicesWithDescriptions
13
16
  from .descriptors import GegevensGroepType
14
17
 
15
18
  try:
16
19
  # 1.1.x
17
- from relativedeltafield.utils import format_relativedelta, relativedelta
20
+ from relativedeltafield.utils import format_relativedelta, parse_relativedelta
18
21
  except ImportError:
19
22
  try:
20
23
  # 1.0.x
21
- from relativedeltafield import format_relativedelta, relativedelta
24
+ from relativedeltafield import format_relativedelta, parse_relativedelta
22
25
  except ImportError:
23
26
  format_relativedelta = None
24
- relativedelta = None
27
+ parse_relativedelta = None
25
28
 
26
29
 
27
30
  class DurationField(fields.DurationField):
28
31
  def to_internal_value(self, value):
29
- if isinstance(value, datetime.timedelta):
32
+ if isinstance(value, relativedelta):
30
33
  return value
31
34
  try:
32
- parsed = isodate.parse_duration(str(value))
33
- except isodate.ISO8601Error:
35
+ return parse_relativedelta(str(value))
36
+ except ValueError:
34
37
  self.fail("invalid", format="P(n)Y(n)M(n)D")
35
- else:
36
- if isinstance(parsed, isodate.Duration):
37
- # TODO: start should probably be a proper object, but we should
38
- # really switch to relativedeltafield
39
- parsed = parsed.totimedelta(start=datetime.datetime.now())
40
- assert isinstance(parsed, datetime.timedelta)
41
- return parsed
42
38
 
43
39
  def to_representation(self, value) -> Optional[str]:
44
- if relativedelta and isinstance(value, relativedelta):
45
- # relativedeltafield 1.1.2 returns a relativedelta() object with no duration,
46
- # to keep behaviour consistent with older versions, change that to `None`
47
- if not value:
48
- return None
40
+ if isinstance(value, relativedelta):
49
41
  return format_relativedelta(value)
50
-
51
- return isodate.duration_isoformat(value)
42
+ return None
52
43
 
53
44
 
54
45
  class FieldValidationErrorSerializer(serializers.Serializer):
@@ -164,11 +155,11 @@ class GegevensGroepSerializer(
164
155
 
165
156
  Usage::
166
157
 
167
- >>> class VerlengingSerializer(GegevensGroepSerializer):
168
- ... class Meta:
169
- ... model = Zaak
170
- ... gegevensgroep = 'verlenging'
171
- >>>
158
+ >>> class VerlengingSerializer(GegevensGroepSerializer):
159
+ ... class Meta:
160
+ ... model = Zaak
161
+ ... gegevensgroep = 'verlenging'
162
+ >>>
172
163
 
173
164
  Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``.
174
165
  """
@@ -275,7 +266,77 @@ class NestedGegevensGroepMixin:
275
266
  return super().update(instance, validated_data)
276
267
 
277
268
 
278
- class LengthHyperlinkedRelatedField(serializers.HyperlinkedRelatedField):
269
+ def get_nested_fk_attribute(instance, relation_path):
270
+ """
271
+ Retrieves an attribute from a nested foreign key relation.
272
+
273
+ Args:
274
+ - instance: The model instance (e.g., Book).
275
+ - relation_path: A string with the relation path, e.g., 'author__publisher__name'.
276
+
277
+ Returns:
278
+ - The value of the nested attribute or None if not found.
279
+ """
280
+ relations = relation_path.split("__")
281
+
282
+ return reduce(
283
+ lambda obj, attr: getattr(obj, attr, None) if obj else None, relations, instance
284
+ )
285
+
286
+
287
+ class CacheMixin:
288
+ """
289
+ Mixin for Hyperlinked DRF fields to cache the base URI per view, to avoid
290
+ having to recalculate this for each related object that has to be serialized
291
+
292
+ This cache is stored on the field instance itself, so it's reset between requests
293
+ """
294
+
295
+ lookup_url_kwarg = "" # Should be defined on `HyperlinkedRelatedField`
296
+ identifier_placeholder = "id-placeholder"
297
+
298
+ def get_extra_reverse_kwargs(self) -> dict[str, str]:
299
+ """
300
+ Hook to inject extra kwargs to be passed to `reverse()`
301
+ """
302
+ return {}
303
+
304
+ def __init__(self, *args, **kwargs):
305
+ super().__init__(*args, **kwargs)
306
+
307
+ self._reverse_cache = {}
308
+
309
+ def get_url(
310
+ self, obj: Model, view_name: str, request: Request, format: str | None
311
+ ) -> str | None:
312
+ # Unsaved objects will not yet have a valid URL.
313
+ if hasattr(obj, "pk") and obj.pk in (None, ""):
314
+ return None
315
+
316
+ base_url = self._reverse_cache.get(view_name)
317
+
318
+ if base_url is None:
319
+ # If not cached, compute and cache it for this request cycle
320
+ try:
321
+ # Insert placeholders for identifiers, these will be replaced by
322
+ # real identifiers later on
323
+ kwargs = {self.lookup_url_kwarg: self.identifier_placeholder}
324
+ kwargs.update(self.get_extra_reverse_kwargs())
325
+
326
+ base_url = self.reverse(
327
+ view_name, kwargs=kwargs, request=request, format=format
328
+ )
329
+ self._reverse_cache[view_name] = base_url
330
+ except Exception as e:
331
+ raise ValueError(f"Could not resolve reverse for {view_name}: {e}")
332
+
333
+ url = base_url.replace(
334
+ self.identifier_placeholder, str(getattr(obj, self.lookup_url_kwarg))
335
+ )
336
+ return url
337
+
338
+
339
+ class LengthHyperlinkedRelatedField(CacheMixin, serializers.HyperlinkedRelatedField):
279
340
  default_error_messages = {
280
341
  "max_length": _("Ensure this field has no more than {max_length} characters."),
281
342
  "min_length": _("Ensure this field has at least {min_length} characters."),
@@ -296,3 +357,40 @@ class LengthHyperlinkedRelatedField(serializers.HyperlinkedRelatedField):
296
357
  self.fail("min_length", max_length=self.min_length, length=len(data))
297
358
 
298
359
  return super().to_internal_value(data)
360
+
361
+
362
+ class CachedHyperlinkedRelatedField(CacheMixin, serializers.HyperlinkedRelatedField):
363
+ """
364
+ Subclass of ``serializers.HyperlinkedRelatedField`` that applies caching in
365
+ ``.get_url()`` to ``reverse()`` calls to improve serialization performance
366
+ """
367
+
368
+
369
+ class CachedHyperlinkedIdentityField(CacheMixin, serializers.HyperlinkedIdentityField):
370
+ """
371
+ Subclass of ``serializers.HyperlinkedIdentityField`` that applies caching in
372
+ ``.get_url()`` to ``reverse()`` calls to improve serialization performance
373
+ """
374
+
375
+
376
+ class CachedNestedHyperlinkedRelatedField(CacheMixin, NestedHyperlinkedRelatedField):
377
+ """
378
+ Subclass of ``serializers.HyperlinkedIdentityField`` that applies caching in
379
+ ``.get_url()`` to ``reverse()`` calls to improve serialization performance
380
+ """
381
+
382
+ def get_extra_reverse_kwargs(self) -> dict[str, str]:
383
+ return self.parent_lookup_kwargs
384
+
385
+ def get_url(
386
+ self, obj: Model, view_name: str, request: Request, format: str | None
387
+ ) -> str | None:
388
+ url = super().get_url(obj, view_name, request, format)
389
+
390
+ if not url:
391
+ return None
392
+
393
+ # Replace the placeholder from the cached base URI with the actual identifier
394
+ for k, v in self.parent_lookup_kwargs.items():
395
+ url = url.replace(v, str(get_nested_fk_attribute(obj, v)))
396
+ return url
@@ -1 +0,0 @@
1
- __version__ = "2.5.5"