django-pfx 1.4.dev50__tar.gz → 1.4.dev52__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 (143) hide show
  1. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/PKG-INFO +1 -1
  2. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/django_pfx.egg-info/PKG-INFO +1 -1
  3. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/django_pfx.egg-info/SOURCES.txt +1 -0
  4. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/api.views.rst +83 -0
  5. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/generate_openapi.md +49 -0
  6. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/apidoc/parameters.py +4 -4
  7. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/decorator/rest.py +2 -1
  8. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.po +3 -3
  9. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/management/commands/makeapidoc.py +8 -0
  10. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/test.py +6 -0
  11. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/groups.py +2 -0
  12. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/rest_views.py +2 -1
  13. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/__init__.py +1 -0
  14. django_pfx-1.4.dev52/tests/tests/test_api_doc_search.py +110 -0
  15. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/.gitignore +0 -0
  16. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/.gitlab-ci.yml +0 -0
  17. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/.pre-commit-config.yaml +0 -0
  18. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/LICENSE +0 -0
  19. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/MANIFEST.in +0 -0
  20. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/README.md +0 -0
  21. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/django_pfx.egg-info/dependency_links.txt +0 -0
  22. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/django_pfx.egg-info/requires.txt +0 -0
  23. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/django_pfx.egg-info/top_level.txt +0 -0
  24. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/Makefile +0 -0
  25. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/conf.py +0 -0
  26. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/index.rst +0 -0
  27. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/authentication.md +0 -0
  28. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/decorator.md +0 -0
  29. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/getting_started.md +0 -0
  30. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/internationalisation.md +0 -0
  31. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/model.md +0 -0
  32. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/pfx_views.md +0 -0
  33. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/profiling.md +0 -0
  34. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/settings.md +0 -0
  35. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/doc/source/testing.md +0 -0
  36. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/img/pfx.png +0 -0
  37. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/img/pfx.svg +0 -0
  38. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/make_messages +0 -0
  39. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/manage.py +0 -0
  40. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/__init__.py +0 -0
  41. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/__init__.py +0 -0
  42. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/apidoc/__init__.py +0 -0
  43. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/apidoc/schema.py +0 -0
  44. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/apidoc/tags.py +0 -0
  45. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/apps.py +0 -0
  46. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/decorator/__init__.py +0 -0
  47. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/default_settings.py +0 -0
  48. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/exceptions.py +0 -0
  49. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/fields.py +0 -0
  50. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/http/__init__.py +0 -0
  51. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/http/json_response.py +0 -0
  52. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/locale/fr/LC_MESSAGES/django.mo +0 -0
  53. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/management/__init__.py +0 -0
  54. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/management/commands/__init__.py +0 -0
  55. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/management/commands/profile.py +0 -0
  56. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/middleware/__init__.py +0 -0
  57. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/middleware/authentication.py +0 -0
  58. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/middleware/locale.py +0 -0
  59. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/middleware/profiling.py +0 -0
  60. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/migrations/0001_initial.py +0 -0
  61. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/migrations/__init__.py +0 -0
  62. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/models/__init__.py +0 -0
  63. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/models/abstract_pfx_base_user.py +0 -0
  64. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/models/cache_mixins.py +0 -0
  65. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/models/login_ban.py +0 -0
  66. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/models/not_null_fields.py +0 -0
  67. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/models/otp_user_mixin.py +0 -0
  68. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/models/pfx_models.py +0 -0
  69. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/models/pfx_user.py +0 -0
  70. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/models/user_filtered_queryset_mixin.py +0 -0
  71. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/serializers/__init__.py +0 -0
  72. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/serializers/json.py +0 -0
  73. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/settings.py +0 -0
  74. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/shortcuts.py +0 -0
  75. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/storage/__init__.py +0 -0
  76. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/storage/s3_storage.py +0 -0
  77. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/templates/registration/otp_code_email.txt +0 -0
  78. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/templates/registration/otp_code_subject.txt +0 -0
  79. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/templates/registration/password_reset_email.txt +0 -0
  80. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/templates/registration/password_reset_subject.txt +0 -0
  81. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/templates/registration/welcome_email.txt +0 -0
  82. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/templates/registration/welcome_subject.txt +0 -0
  83. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/urls.py +0 -0
  84. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/__init__.py +0 -0
  85. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/authentication_views.py +0 -0
  86. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/fields.py +0 -0
  87. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/filters_views.py +0 -0
  88. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/locale_views.py +0 -0
  89. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/__init__.py +0 -0
  90. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/date_format.py +0 -0
  91. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/list_count.py +0 -0
  92. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/list_items.py +0 -0
  93. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/list_mode.py +0 -0
  94. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/list_order.py +0 -0
  95. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/list_search.py +0 -0
  96. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/media_redirect.py +0 -0
  97. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/meta_fields.py +0 -0
  98. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/meta_filters.py +0 -0
  99. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/meta_orders.py +0 -0
  100. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/subset.py +0 -0
  101. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/subset_limit.py +0 -0
  102. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/subset_offset.py +0 -0
  103. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/subset_page.py +0 -0
  104. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/subset_page_size.py +0 -0
  105. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/pfxcore/views/parameters/subset_page_subset.py +0 -0
  106. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/settings/__init__.py +0 -0
  107. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pfx/settings/dev.py +0 -0
  108. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/pyproject.toml +0 -0
  109. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/requirements.txt +0 -0
  110. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/serve-doc +0 -0
  111. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/setup.cfg +0 -0
  112. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/setup.py +0 -0
  113. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/__init__.py +0 -0
  114. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/locale/fr/LC_MESSAGES/django.po +0 -0
  115. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/models.py +0 -0
  116. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/settings/__init__.py +0 -0
  117. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/settings/ci.py +0 -0
  118. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/settings/common.py +0 -0
  119. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/settings/dev.py +0 -0
  120. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/settings/dev_custom_example.py +0 -0
  121. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/settings/dev_default.py +0 -0
  122. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/basic_api_errors.py +0 -0
  123. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/basic_api_test.py +0 -0
  124. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_api_doc.py +0 -0
  125. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_auth_api.py +0 -0
  126. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_body_mixin.py +0 -0
  127. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_cache.py +0 -0
  128. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_client.py +0 -0
  129. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_fields.py +0 -0
  130. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_filters.py +0 -0
  131. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_locale_api.py +0 -0
  132. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_perm_tests.py +0 -0
  133. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_perms_api.py +0 -0
  134. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_profiling_middleware.py +0 -0
  135. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_settings.py +0 -0
  136. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_shortcuts.py +0 -0
  137. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_timezone_middleware.py +0 -0
  138. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_tools.py +0 -0
  139. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_user_queryset.py +0 -0
  140. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_view_decorators.py +0 -0
  141. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/tests/test_view_fields.py +0 -0
  142. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/urls.py +0 -0
  143. {django_pfx-1.4.dev50 → django_pfx-1.4.dev52}/tests/views.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-pfx
3
- Version: 1.4.dev50
3
+ Version: 1.4.dev52
4
4
  Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-pfx
3
- Version: 1.4.dev50
3
+ Version: 1.4.dev52
4
4
  Summary: Django PFX is a toolkit designed to streamline the development of RESTful APIs using the Django framework.
5
5
  Author: Hervé Martinet
6
6
  Author-email: herve.martinet@gmail.com
@@ -122,6 +122,7 @@ tests/tests/__init__.py
122
122
  tests/tests/basic_api_errors.py
123
123
  tests/tests/basic_api_test.py
124
124
  tests/tests/test_api_doc.py
125
+ tests/tests/test_api_doc_search.py
125
126
  tests/tests/test_auth_api.py
126
127
  tests/tests/test_body_mixin.py
127
128
  tests/tests/test_cache.py
@@ -47,6 +47,89 @@ API Reference
47
47
  ``pfx.pfxcore.views``
48
48
  *********************
49
49
 
50
+ Query parameters & groups
51
+ -------------------------
52
+
53
+ .. autoclass:: pfx.pfxcore.views.parameters.ListCount
54
+ :members:
55
+ :undoc-members:
56
+ :show-inheritance:
57
+
58
+ .. autoclass:: pfx.pfxcore.views.parameters.ListItems
59
+ :members:
60
+ :undoc-members:
61
+ :show-inheritance:
62
+
63
+ .. autoclass:: pfx.pfxcore.views.parameters.ListMode
64
+ :members:
65
+ :undoc-members:
66
+ :show-inheritance:
67
+
68
+ .. autoclass:: pfx.pfxcore.views.parameters.ListOrder
69
+ :members:
70
+ :undoc-members:
71
+ :show-inheritance:
72
+
73
+ .. autoclass:: pfx.pfxcore.views.parameters.ListSearch
74
+ :members:
75
+ :undoc-members:
76
+ :show-inheritance:
77
+
78
+ .. autoclass:: pfx.pfxcore.views.parameters.MediaRedirect
79
+ :members:
80
+ :undoc-members:
81
+ :show-inheritance:
82
+
83
+ .. autoclass:: pfx.pfxcore.views.parameters.MetaFields
84
+ :members:
85
+ :undoc-members:
86
+ :show-inheritance:
87
+
88
+ .. autoclass:: pfx.pfxcore.views.parameters.groups.MetaFilters
89
+ :members:
90
+ :undoc-members:
91
+ :show-inheritance:
92
+
93
+ .. autoclass:: pfx.pfxcore.views.parameters.groups.MetaOrders
94
+ :members:
95
+ :undoc-members:
96
+ :show-inheritance:
97
+
98
+ .. autoclass:: pfx.pfxcore.views.parameters.groups.SubsetLimit
99
+ :members:
100
+ :undoc-members:
101
+ :show-inheritance:
102
+
103
+ .. autoclass:: pfx.pfxcore.views.parameters.groups.SubsetOffset
104
+ :members:
105
+ :undoc-members:
106
+ :show-inheritance:
107
+
108
+ .. autoclass:: pfx.pfxcore.views.parameters.groups.SubsetPageSize
109
+ :members:
110
+ :undoc-members:
111
+ :show-inheritance:
112
+
113
+ .. autoclass:: pfx.pfxcore.views.parameters.groups.SubsetPageSubset
114
+ :members:
115
+ :undoc-members:
116
+ :show-inheritance:
117
+
118
+ .. autoclass:: pfx.pfxcore.views.parameters.groups.SubsetPage
119
+ :members:
120
+ :undoc-members:
121
+ :show-inheritance:
122
+
123
+ .. autoclass:: pfx.pfxcore.views.parameters.groups.MetaList
124
+ :members:
125
+ :undoc-members:
126
+ :show-inheritance:
127
+
128
+ .. autoclass:: pfx.pfxcore.views.parameters.groups.List
129
+ :members:
130
+ :undoc-members:
131
+ :show-inheritance:
132
+
50
133
  Base services
51
134
  -------------
52
135
 
@@ -158,6 +158,55 @@ from .parameters import ListGroup
158
158
  @rest_api("/", method="get", parameters=[ListGroup])
159
159
  ```
160
160
 
161
+ #### Pre defined query parameters
162
+
163
+ A number of predefined parameters and groups are used by view mixins, and are reusable and inheritable:
164
+ See [API reference | Query parameters & groups](api.views.rst#query-parameters-groups) for details.
165
+
166
+ For {class}`pfx.pfxcore.views.parameters.ListSearch`, you can redefine the behaviour by annotation:
167
+ either with `@rest_doc` on the view (useful if the view inherits from {class}`pfx.pfxcore.views.ListRestViewMixin`),
168
+ or with `@rest_api` on the service (useful if you reuse the {class}`pfx.pfxcore.views.parameters.ListSearch` parameter
169
+ or the {class}`pfx.pfxcore.views.parameters.groups.List` group).
170
+
171
+ ```python
172
+ from pfx.pfxcore.decorator.rest import rest_doc, rest_view
173
+ from pfx.pfxcore.views import BaseRestView, ListRestViewMixin
174
+
175
+ # Do not add the search param in api doc:
176
+ @rest_doc("", "get", search=False)
177
+ @rest_view("/my-view")
178
+ class MyView(ListRestViewMixin, BaseRestView):
179
+ pass
180
+ ```
181
+
182
+ ```python
183
+ from pfx.pfxcore.decorator.rest import rest_doc, rest_view
184
+ from pfx.pfxcore.views import BaseRestView, ListRestViewMixin
185
+
186
+ # Customize the search param description in api doc:
187
+ @rest_doc("", "get", search="Search the string in name and summary fields.")
188
+ @rest_view("/my-view")
189
+ class MyView(ListRestViewMixin, BaseRestView):
190
+ pass
191
+ ```
192
+
193
+ ```python
194
+ from pfx.pfxcore.decorator.rest import rest_doc, rest_view
195
+ from pfx.pfxcore.views import BaseRestView
196
+
197
+ @rest_view("/custom")
198
+ class MyView(BaseRestView):
199
+
200
+ # Use parameters.groups.List with custom description for search param:
201
+ @rest_api(
202
+ "", method="get",
203
+ parameters=[parameters.groups.List],
204
+ search="A custom description.")
205
+ def get(self, *args, **kwargs):
206
+ return JsonResponse({})
207
+ ```
208
+
209
+
161
210
  ### Body and response schema
162
211
 
163
212
  When using standard mixins to provide basic Rest services, the body
@@ -21,12 +21,12 @@ class Parameter:
21
21
  return cls.__name__
22
22
 
23
23
  @classmethod
24
- def as_parameter(cls):
24
+ def as_parameter(cls, doc=None):
25
25
  res = dict(name=cls.name)
26
26
  res['in'] = cls.location
27
- doc = inspect.getdoc(cls)
28
- if doc:
29
- res['description'] = doc
27
+ description = doc or inspect.getdoc(cls)
28
+ if description:
29
+ res['description'] = description
30
30
  members = inspect.getmembers(
31
31
  cls, predicate=lambda x: not (
32
32
  inspect.ismethod(x)))
@@ -17,7 +17,7 @@ def rest_api(
17
17
  path, method='get', public=None, priority=0, priority_doc=0,
18
18
  parameters=None,
19
19
  request_schema=None, response_schema=None, filters=False,
20
- groups=None):
20
+ search=False, groups=None):
21
21
  def decorator(func):
22
22
  @wraps(func)
23
23
  def wrapper(self, request, *args, **kwargs):
@@ -47,6 +47,7 @@ def rest_api(
47
47
  wrapper.rest_api_request_schema = request_schema
48
48
  wrapper.rest_api_response_schema = response_schema
49
49
  wrapper.rest_api_filters = filters
50
+ wrapper.rest_api_search = search
50
51
  wrapper.rest_api_groups = set(groups or [])
51
52
  wrapper.rest_api_public = public
52
53
  return wrapper
@@ -7,7 +7,7 @@ msgid ""
7
7
  msgstr ""
8
8
  "Project-Id-Version: \n"
9
9
  "Report-Msgid-Bugs-To: \n"
10
- "POT-Creation-Date: 2024-04-23 14:41+0200\n"
10
+ "POT-Creation-Date: 2024-05-21 15:30+0200\n"
11
11
  "PO-Revision-Date: 2021-06-22 23:31+0200\n"
12
12
  "Last-Translator: \n"
13
13
  "Language-Team: \n"
@@ -275,11 +275,11 @@ msgstr "{model} {obj} créé."
275
275
  msgid "{model} {obj} updated."
276
276
  msgstr "{model} {obj} modifié."
277
277
 
278
- #: views/rest_views.py:1076
278
+ #: views/rest_views.py:1077
279
279
  #, python-brace-format
280
280
  msgid "{model} {obj} deleted."
281
281
  msgstr "{model} {obj} supprimé."
282
282
 
283
- #: views/rest_views.py:1138 views/rest_views.py:1166
283
+ #: views/rest_views.py:1139 views/rest_views.py:1167
284
284
  msgid "Unexpected storage error"
285
285
  msgstr "Erreur de stockage inattendue"
@@ -63,6 +63,14 @@ def global_parameters(spec, method):
63
63
  p.get('name', '#N/A') for p in spec.get('parameters', [])
64
64
  if isinstance(p, dict)}
65
65
  for qp in extend_groups(method.rest_api_params):
66
+ if qp.name == 'search':
67
+ search = (
68
+ spec['search'] if 'search' in spec else method.rest_api_search)
69
+ if not search:
70
+ continue
71
+ if isinstance(search, str):
72
+ yield qp.as_parameter(doc=search)
73
+ continue
66
74
  if qp.name in existings:
67
75
  # Ignore path parameters that are manually described.
68
76
  continue
@@ -255,6 +255,12 @@ class TestAssertMixin:
255
255
  return self.assertIn(
256
256
  element, self.get_val(src, key, msg=msg), msg=msg)
257
257
 
258
+ # assert JSON array contains
259
+ def assertJNotIn(self, src, key, element, msg=None):
260
+ msg = '\n'.join([msg or '', self.format_json(src)])
261
+ return self.assertNotIn(
262
+ element, self.get_val(src, key, msg=msg), msg=msg)
263
+
258
264
 
259
265
  class TestPermsAssertMixin(TestAssertMixin):
260
266
  USER_TESTS = {}
@@ -26,10 +26,12 @@ class ModelSerialization(ParameterGroup):
26
26
 
27
27
 
28
28
  class MetaList(ParameterGroup):
29
+ """Parameters group for meta list services."""
29
30
  parameters = [MetaFields, MetaFilters, MetaOrders]
30
31
 
31
32
 
32
33
  class List(ParameterGroup):
34
+ """Parameters group for list services."""
33
35
  parameters = [
34
36
  ListCount, ListItems, ListSearch, ListOrder, ListMode,
35
37
  Subset, SubsetPage, SubsetPageSize,
@@ -808,7 +808,8 @@ class ListRestViewMixin(ModelResponseMixin):
808
808
  return JsonResponse(res)
809
809
 
810
810
  @rest_api(
811
- "", method="get", parameters=[parameters.groups.List], filters=True,
811
+ "", method="get", parameters=[parameters.groups.List],
812
+ filters=True, search=True,
812
813
  response_schema='model_list_schema', priority_doc=-20)
813
814
  def get_list(self, *args, **kwargs):
814
815
  """Entrypoint for :code:`GET /` route.
@@ -1,6 +1,7 @@
1
1
  from .basic_api_errors import BasicAPIErrorTest
2
2
  from .basic_api_test import BasicAPITest
3
3
  from .test_api_doc import ApiDocTest
4
+ from .test_api_doc_search import TestAPIDocSearch
4
5
  from .test_auth_api import AuthAPITest
5
6
  from .test_body_mixin import TestBodyMixin
6
7
  from .test_cache import TestCache
@@ -0,0 +1,110 @@
1
+ from django.http import JsonResponse
2
+ from django.test import TestCase, override_settings
3
+ from django.urls import include, path
4
+
5
+ from pfx.pfxcore.decorator.rest import rest_api, rest_doc, rest_view
6
+ from pfx.pfxcore.management.commands.makeapidoc import get_spec
7
+ from pfx.pfxcore.shortcuts import register_views
8
+ from pfx.pfxcore.test import APIClient, TestAssertMixin
9
+ from pfx.pfxcore.views import (
10
+ BaseRestView,
11
+ ListRestViewMixin,
12
+ ModelResponseMixin,
13
+ parameters,
14
+ )
15
+ from tests.models import Author
16
+
17
+
18
+ @rest_view("/list/default")
19
+ class DefaultListView(ListRestViewMixin, ModelResponseMixin, BaseRestView):
20
+ model = Author
21
+ default_public = True
22
+
23
+
24
+ @rest_doc("", "get", search=False)
25
+ @rest_view("/list/no-search")
26
+ class NoSearchListView(ListRestViewMixin, ModelResponseMixin, BaseRestView):
27
+ model = Author
28
+ default_public = True
29
+
30
+
31
+ @rest_doc("", "get", search="A custom description.")
32
+ @rest_view("/list/custom-description")
33
+ class CustomDescriptionListView(
34
+ ListRestViewMixin, ModelResponseMixin, BaseRestView):
35
+ model = Author
36
+ default_public = True
37
+
38
+
39
+ @rest_view("/custom")
40
+ class CustomServiceView(BaseRestView):
41
+ model = Author
42
+ default_public = True
43
+
44
+ @rest_api(
45
+ "/default", method="get", parameters=[parameters.groups.List],
46
+ search=True)
47
+ def get_default(self, *args, **kwargs):
48
+ return JsonResponse({})
49
+
50
+ @rest_api(
51
+ "/no-search", method="get", parameters=[parameters.groups.List],
52
+ search=False)
53
+ def get_no_search(self, *args, **kwargs):
54
+ return JsonResponse({})
55
+
56
+ @rest_api(
57
+ "/custom-description", method="get",
58
+ parameters=[parameters.groups.List],
59
+ search="A custom description.")
60
+ def get_custom_description(self, *args, **kwargs):
61
+ return JsonResponse({})
62
+
63
+
64
+ urlpatterns = [
65
+ path('api/', include(register_views(
66
+ DefaultListView,
67
+ NoSearchListView,
68
+ CustomDescriptionListView,
69
+ CustomServiceView))),
70
+ path('api/', include('pfx.pfxcore.urls'))
71
+ ]
72
+
73
+
74
+ @override_settings(ROOT_URLCONF=__name__)
75
+ class TestAPIDocSearch(TestAssertMixin, TestCase):
76
+ def setUp(self):
77
+ self.client = APIClient(default_locale='en')
78
+
79
+ def test_body_to_model(self):
80
+ def get_params(spec, path):
81
+ for p in self.get_val(spec, f'paths.{path}.get.parameters'):
82
+ yield p.get('$ref') or p.get('name'), p
83
+
84
+ spec = get_spec(set()).to_dict()
85
+
86
+ params = dict(get_params(spec, '/list/default'))
87
+ self.assertJEExists(params, '#/components/parameters/ListSearch')
88
+ self.assertJENotExists(params, 'search')
89
+
90
+ params = dict(get_params(spec, '/list/no-search'))
91
+ self.assertJENotExists(params, '#/components/parameters/ListSearch')
92
+ self.assertJENotExists(params, 'search')
93
+
94
+ params = dict(get_params(spec, '/list/custom-description'))
95
+ self.assertJENotExists(params, '#/components/parameters/ListSearch')
96
+ self.assertJEExists(params, 'search')
97
+ self.assertJE(params, 'search.description', "A custom description.")
98
+
99
+ params = dict(get_params(spec, '/custom/default'))
100
+ self.assertJEExists(params, '#/components/parameters/ListSearch')
101
+ self.assertJENotExists(params, 'search')
102
+
103
+ params = dict(get_params(spec, '/custom/no-search'))
104
+ self.assertJENotExists(params, '#/components/parameters/ListSearch')
105
+ self.assertJENotExists(params, 'search')
106
+
107
+ params = dict(get_params(spec, '/custom/custom-description'))
108
+ self.assertJENotExists(params, '#/components/parameters/ListSearch')
109
+ self.assertJEExists(params, 'search')
110
+ self.assertJE(params, 'search.description', "A custom description.")
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes