django-api-admin 1.2.1__tar.gz → 1.2.3__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 (103) hide show
  1. django_api_admin-1.2.3/LICENSE-DJANGO +27 -0
  2. django_api_admin-1.2.3/LICENSE-RESTFUL-ADMIN +21 -0
  3. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/PKG-INFO +32 -37
  4. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/README.md +20 -7
  5. django_api_admin-1.2.3/assets/images/logo.png +0 -0
  6. django_api_admin-1.2.3/assets/images/screenshot.png +0 -0
  7. django_api_admin-1.2.3/django_api_admin/admin_views/admin_site_views/admin_api_root.py +51 -0
  8. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/app_index.py +1 -0
  9. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/index.py → django_api_admin-1.2.3/django_api_admin/admin_views/admin_site_views/app_list.py +3 -4
  10. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/autocomplete.py +12 -1
  11. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/language_catalog.py +2 -2
  12. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/site_context.py +0 -2
  13. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/model_admin_views/add.py +21 -19
  14. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/model_admin_views/change.py +7 -3
  15. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/model_admin_views/detail.py +3 -3
  16. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/model_admin_views/history.py +1 -2
  17. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/model_admin_views/list.py +0 -4
  18. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admins/base_admin.py +23 -12
  19. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admins/inline_admin.py +22 -13
  20. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admins/model_admin.py +39 -28
  21. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/changelist.py +12 -0
  22. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/checks.py +13 -1
  23. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/decorators.py +14 -0
  24. django_api_admin-1.2.3/django_api_admin/exceptions.py +49 -0
  25. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/filters.py +8 -1
  26. django_api_admin-1.2.3/django_api_admin/hooks.py +99 -0
  27. django_api_admin-1.2.3/django_api_admin/locale/ar/LC_MESSAGES/django.po +671 -0
  28. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/models.py +12 -0
  29. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/openapi.py +22 -0
  30. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/serializers.py +8 -0
  31. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/sites.py +105 -76
  32. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/_get_non_gfk_field.py +7 -0
  33. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/diff_helper.py +6 -0
  34. django_api_admin-1.2.3/django_api_admin/utils/flatten.py +18 -0
  35. django_api_admin-1.2.3/django_api_admin/utils/get_content_type_for_model.py +13 -0
  36. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/get_deleted_objects.py +7 -0
  37. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/get_field_attributes.py +0 -1
  38. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/get_fields_from_path.py +7 -0
  39. django_api_admin-1.2.3/django_api_admin/utils/get_form_config.py +8 -0
  40. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/get_form_fields.py +10 -9
  41. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/get_inline_by_field_name.py +1 -4
  42. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/get_inlines.py +10 -7
  43. django_api_admin-1.2.3/django_api_admin/utils/get_model_from_relation.py +15 -0
  44. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/get_related_name.py +1 -4
  45. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/label_for_field.py +7 -0
  46. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/lookup_field.py +7 -0
  47. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/lookup_spawns_duplicates.py +7 -0
  48. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/model_format_dict.py +7 -0
  49. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/model_ngettext.py +7 -0
  50. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/nested_objects.py +7 -0
  51. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/prepare_lookup_value.py +7 -0
  52. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/quote.py +7 -0
  53. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/reverse_field_path.py +7 -0
  54. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/url_params_from_lookup_dict.py +7 -0
  55. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/validate_bulk_edits.py +51 -47
  56. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/validate_inline_field_names.py +5 -5
  57. django_api_admin-1.2.3/pyproject.toml +47 -0
  58. django_api_admin-1.2.1/django_api_admin/admin_views/admin_site_views/admin_api_root.py +0 -23
  59. django_api_admin-1.2.1/django_api_admin/exceptions.py +0 -31
  60. django_api_admin-1.2.1/django_api_admin/hooks.py +0 -67
  61. django_api_admin-1.2.1/django_api_admin/utils/flatten.py +0 -11
  62. django_api_admin-1.2.1/django_api_admin/utils/get_content_type_for_model.py +0 -6
  63. django_api_admin-1.2.1/django_api_admin/utils/get_form_config.py +0 -13
  64. django_api_admin-1.2.1/django_api_admin/utils/get_model_from_relation.py +0 -8
  65. django_api_admin-1.2.1/django_api_admin.egg-info/PKG-INFO +0 -369
  66. django_api_admin-1.2.1/django_api_admin.egg-info/SOURCES.txt +0 -88
  67. django_api_admin-1.2.1/django_api_admin.egg-info/dependency_links.txt +0 -1
  68. django_api_admin-1.2.1/django_api_admin.egg-info/requires.txt +0 -7
  69. django_api_admin-1.2.1/django_api_admin.egg-info/top_level.txt +0 -2
  70. django_api_admin-1.2.1/pyproject.toml +0 -44
  71. django_api_admin-1.2.1/setup.cfg +0 -4
  72. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/LICENSE +0 -0
  73. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/__init__.py +0 -0
  74. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/actions.py +0 -0
  75. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/__init__.py +0 -0
  76. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/admin_log.py +0 -0
  77. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/obtain_token.py +0 -0
  78. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/password_change.py +0 -0
  79. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/token_refresh.py +0 -0
  80. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/user_information.py +0 -0
  81. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/admin_site_views/view_on_site.py +0 -0
  82. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/model_admin_views/__init__.py +0 -0
  83. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/model_admin_views/changelist.py +0 -0
  84. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/model_admin_views/delete.py +1 -1
  85. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admin_views/model_admin_views/handle_action.py +0 -0
  86. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/admins/__init__.py +0 -0
  87. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/apps.py +0 -0
  88. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/constants/__init__.py +0 -0
  89. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/constants/field_attributes.py +0 -0
  90. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/constants/vars.py +0 -0
  91. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/declarations/__init__.py +0 -0
  92. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/declarations/functions.py +0 -0
  93. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/migrations/0001_initial.py +0 -0
  94. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/migrations/__init__.py +0 -0
  95. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/options.py +0 -0
  96. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/pagination.py +0 -0
  97. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/permissions.py +0 -0
  98. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/__init__.py +0 -0
  99. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/force_login.py +0 -0
  100. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/utils/remove_field.py +0 -0
  101. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/views/__init__.py +0 -0
  102. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/views/admin_views.py +0 -0
  103. {django_api_admin-1.2.1 → django_api_admin-1.2.3}/django_api_admin/views/site_views.py +0 -0
@@ -0,0 +1,27 @@
1
+ Copyright (c) Django Software Foundation and individual contributors.
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ 1. Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+
10
+ 2. Redistributions in binary form must reproduce the above copyright
11
+ notice, this list of conditions and the following disclaimer in the
12
+ documentation and/or other materials provided with the distribution.
13
+
14
+ 3. Neither the name of Django nor the names of its contributors may be used
15
+ to endorse or promote products derived from this software without
16
+ specific prior written permission.
17
+
18
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 amirasaran
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,42 +1,24 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: django-api-admin
3
- Version: 1.2.1
3
+ Version: 1.2.3
4
4
  Summary: A RESTful API implementation of django.contrib.admin, designed for writing custom frontends.
5
+ Author: Muhammad Salah
5
6
  Author-email: Muhammad Salah <msbizzacc0unt@outlook.com>
6
- License: MIT License
7
-
8
- Copyright (c) 2021 Muhammad Salah
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- copies of the Software, and to permit persons to whom the Software is
15
- furnished to do so, subject to the following conditions:
16
-
17
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
27
-
28
- Project-URL: Github, https://github.com/demon-bixia/django-api-admin
7
+ License-File: LICENSE
8
+ License-File: LICENSE-DJANGO
9
+ License-File: LICENSE-RESTFUL-ADMIN
29
10
  Classifier: Programming Language :: Python :: 3
30
11
  Classifier: License :: OSI Approved :: MIT License
31
12
  Classifier: Operating System :: OS Independent
32
- Description-Content-Type: text/markdown
33
- License-File: LICENSE
34
13
  Requires-Dist: django
35
14
  Requires-Dist: djangorestframework
36
- Requires-Dist: djangorestframework-simplejwt
37
15
  Requires-Dist: drf-spectacular
38
- Provides-Extra: dev
39
- Requires-Dist: django-cors-headers; extra == "dev"
16
+ Requires-Dist: djangorestframework-simplejwt
17
+ Requires-Dist: django-cors-headers ; extra == 'example'
18
+ Requires-Dist: python-dotenv>=1.1.1 ; extra == 'example'
19
+ Project-URL: Github, https://github.com/demon-bixia/django-api-admin
20
+ Provides-Extra: example
21
+ Description-Content-Type: text/markdown
40
22
 
41
23
  <a id="readme-top"></a>
42
24
 
@@ -69,9 +51,9 @@ Requires-Dist: django-cors-headers; extra == "dev"
69
51
  <!-- <br /> -->
70
52
  <!-- <a href="https://github.com/othneildrew/Best-README-Template">View Demo</a>
71
53
  &middot; -->
72
- <a href="https://github.com/othneildrew/Best-README-Template/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
54
+ <a href="https://github.com/demon-bixia/django-api-admin/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
73
55
  &middot;
74
- <a href="https://github.com/othneildrew/Best-README-Template/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
56
+ <a href="https://github.com/demon-bixia/django-api-admin/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
75
57
  </p>
76
58
  </div>
77
59
 
@@ -108,7 +90,7 @@ Requires-Dist: django-cors-headers; extra == "dev"
108
90
  <!-- ABOUT THE PROJECT -->
109
91
  ## About The Project
110
92
 
111
- [![Product Name Screen Shot][product-screenshot]](https://example.com)
93
+ [![Product Name Screen Shot][product-screenshot]](https://github.com/demon-bixia/django-api-admin)
112
94
 
113
95
  The Django API Admin project is a RESTful API implementation of the `django.contrib.admin` module, designed to facilitate the creation of custom frontends. This project aims to provide developers with a robust and flexible API that mirrors the functionality of Django's built-in admin interface, allowing for seamless integration with modern web applications.
114
96
 
@@ -204,6 +186,16 @@ This guide will walk you through the steps to integrate `django-api-admin` into
204
186
  )
205
187
  CORS_ALLOW_CREDENTIALS = True
206
188
  ```
189
+ 5. **Add the modify_schema hook** used to tag paths in the openapi schema
190
+ ```py
191
+ # settings.py
192
+ SPECTACULAR_SETTINGS = {
193
+ "POSTPROCESSING_HOOKS": [
194
+ 'drf_spectacular.hooks.postprocess_schema_enums',
195
+ 'django_api_admin.hooks.modify_schema'
196
+ ]
197
+ }
198
+ ```
207
199
 
208
200
  Thats it you are now ready to register your models and implement your django admin frontend!
209
201
 
@@ -249,8 +241,11 @@ This section provides a simple example on how to use django-api-admin. If you're
249
241
  from django.urls import path
250
242
  from django_api_admin.sites import site
251
243
 
244
+ # the admin site needs to know the name of the url prefix in this case "admin/"
245
+ # the default is just the admin site's name which is "admin" + "/"
246
+ # for the default admin site
252
247
  urlpatterns = [
253
- path('api_admin/', site.urls),
248
+ path('admin/', site.urls),
254
249
  ]
255
250
  ```
256
251
 
@@ -271,7 +266,7 @@ This section provides a simple example on how to use django-api-admin. If you're
271
266
  - [ ] Oauth support
272
267
  - [ ] Multi-language Support
273
268
  - [ ] Arabic
274
- - [ ] Spanish
269
+ - [x] English
275
270
 
276
271
  See the [open issues](https://github.com/demon-bixia/django-api-admin/issues) for a full list of proposed features (and known issues).
277
272
 
@@ -333,8 +328,8 @@ This section is dedicated to recognizing the valuable resources and contribution
333
328
  * [Simple JWT](https://github.com/jazzband/djangorestframework-simplejwt/tree/master)
334
329
  * [Django Cors Headers](https://github.com/adamchainz/django-cors-headers)
335
330
  * [DRF Spectacular](https://github.com/tfranzel/drf-spectacular)
331
+ * [Django Restful Admin](https://github.com/amirasaran/django-restful-admin)
336
332
  * [Best README Template](https://github.com/othneildrew/Best-README-Template)
337
- * [QODO AI](https://www.qodo.ai/)
338
333
 
339
334
  <p align="right">(<a href="#readme-top">back to top</a>)</p>
340
335
 
@@ -342,7 +337,7 @@ This section is dedicated to recognizing the valuable resources and contribution
342
337
 
343
338
  <!-- MARKDOWN LINKS & IMAGES -->
344
339
  <!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
345
- [contributors-shield]: https://img.shields.io/github/contributors/othneildrew/Best-README-Template.svg?style=for-the-badge
340
+ [contributors-shield]: https://img.shields.io/github/contributors/demon-bixia/django-api-admin.svg?style=for-the-badge
346
341
  [contributors-url]: https://github.com/demon-bixia/django-api-admin/graphs/contributors
347
342
 
348
343
  [forks-shield]: https://img.shields.io/github/forks/demon-bixia/django-api-admin.svg?style=for-the-badge
@@ -29,9 +29,9 @@
29
29
  <!-- <br /> -->
30
30
  <!-- <a href="https://github.com/othneildrew/Best-README-Template">View Demo</a>
31
31
  &middot; -->
32
- <a href="https://github.com/othneildrew/Best-README-Template/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
32
+ <a href="https://github.com/demon-bixia/django-api-admin/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
33
33
  &middot;
34
- <a href="https://github.com/othneildrew/Best-README-Template/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
34
+ <a href="https://github.com/demon-bixia/django-api-admin/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
35
35
  </p>
36
36
  </div>
37
37
 
@@ -68,7 +68,7 @@
68
68
  <!-- ABOUT THE PROJECT -->
69
69
  ## About The Project
70
70
 
71
- [![Product Name Screen Shot][product-screenshot]](https://example.com)
71
+ [![Product Name Screen Shot][product-screenshot]](https://github.com/demon-bixia/django-api-admin)
72
72
 
73
73
  The Django API Admin project is a RESTful API implementation of the `django.contrib.admin` module, designed to facilitate the creation of custom frontends. This project aims to provide developers with a robust and flexible API that mirrors the functionality of Django's built-in admin interface, allowing for seamless integration with modern web applications.
74
74
 
@@ -164,6 +164,16 @@ This guide will walk you through the steps to integrate `django-api-admin` into
164
164
  )
165
165
  CORS_ALLOW_CREDENTIALS = True
166
166
  ```
167
+ 5. **Add the modify_schema hook** used to tag paths in the openapi schema
168
+ ```py
169
+ # settings.py
170
+ SPECTACULAR_SETTINGS = {
171
+ "POSTPROCESSING_HOOKS": [
172
+ 'drf_spectacular.hooks.postprocess_schema_enums',
173
+ 'django_api_admin.hooks.modify_schema'
174
+ ]
175
+ }
176
+ ```
167
177
 
168
178
  Thats it you are now ready to register your models and implement your django admin frontend!
169
179
 
@@ -209,8 +219,11 @@ This section provides a simple example on how to use django-api-admin. If you're
209
219
  from django.urls import path
210
220
  from django_api_admin.sites import site
211
221
 
222
+ # the admin site needs to know the name of the url prefix in this case "admin/"
223
+ # the default is just the admin site's name which is "admin" + "/"
224
+ # for the default admin site
212
225
  urlpatterns = [
213
- path('api_admin/', site.urls),
226
+ path('admin/', site.urls),
214
227
  ]
215
228
  ```
216
229
 
@@ -231,7 +244,7 @@ This section provides a simple example on how to use django-api-admin. If you're
231
244
  - [ ] Oauth support
232
245
  - [ ] Multi-language Support
233
246
  - [ ] Arabic
234
- - [ ] Spanish
247
+ - [x] English
235
248
 
236
249
  See the [open issues](https://github.com/demon-bixia/django-api-admin/issues) for a full list of proposed features (and known issues).
237
250
 
@@ -293,8 +306,8 @@ This section is dedicated to recognizing the valuable resources and contribution
293
306
  * [Simple JWT](https://github.com/jazzband/djangorestframework-simplejwt/tree/master)
294
307
  * [Django Cors Headers](https://github.com/adamchainz/django-cors-headers)
295
308
  * [DRF Spectacular](https://github.com/tfranzel/drf-spectacular)
309
+ * [Django Restful Admin](https://github.com/amirasaran/django-restful-admin)
296
310
  * [Best README Template](https://github.com/othneildrew/Best-README-Template)
297
- * [QODO AI](https://www.qodo.ai/)
298
311
 
299
312
  <p align="right">(<a href="#readme-top">back to top</a>)</p>
300
313
 
@@ -302,7 +315,7 @@ This section is dedicated to recognizing the valuable resources and contribution
302
315
 
303
316
  <!-- MARKDOWN LINKS & IMAGES -->
304
317
  <!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
305
- [contributors-shield]: https://img.shields.io/github/contributors/othneildrew/Best-README-Template.svg?style=for-the-badge
318
+ [contributors-shield]: https://img.shields.io/github/contributors/demon-bixia/django-api-admin.svg?style=for-the-badge
306
319
  [contributors-url]: https://github.com/demon-bixia/django-api-admin/graphs/contributors
307
320
 
308
321
  [forks-shield]: https://img.shields.io/github/forks/demon-bixia/django-api-admin.svg?style=for-the-badge
@@ -0,0 +1,51 @@
1
+ from django.utils.translation import gettext_lazy as _
2
+
3
+ from rest_framework import status
4
+ from rest_framework.response import Response
5
+ from rest_framework.views import APIView
6
+ from rest_framework.reverse import reverse
7
+
8
+ from drf_spectacular.utils import extend_schema, OpenApiResponse
9
+
10
+ from django_api_admin.openapi import CommonAPIResponses, APIResponseExamples
11
+ from django_api_admin.serializers import APIRootSerializer
12
+
13
+
14
+ class AdminAPIRootView(APIView):
15
+ """
16
+ A list of urls that act as a starting point for browsing the REST API
17
+ """
18
+ root_urls = None
19
+ admin_site = None
20
+
21
+ @extend_schema(
22
+ responses={
23
+ 200: OpenApiResponse(
24
+ description=_(
25
+ "A list of urls that act as a starting point for browsing the REST API"),
26
+ response=APIRootSerializer,
27
+ examples=[APIResponseExamples.root_urls()]
28
+ ),
29
+ 401: CommonAPIResponses.unauthorized()
30
+ }
31
+ )
32
+ def get(self, request, ):
33
+ namespace = request.resolver_match.namespace
34
+ data = dict()
35
+
36
+ for url in self.root_urls:
37
+ # Include the app_index url for every app
38
+ if url.name == 'app_index':
39
+ valid_app_labels = set(model._meta.app_label for model,
40
+ _ in self.admin_site._registry.items())
41
+ for app_label in valid_app_labels:
42
+ data[f'{app_label}_{url.name}'] = reverse(
43
+ f'{namespace}:{url.name}', kwargs={"app_label": app_label}, request=request)
44
+
45
+ # Include the rest of the urls except the view_on_site
46
+ # todo: consider including the view_on_site url index every object's detail view response
47
+ elif url.name != "view_on_site":
48
+ data[url.name] = reverse(
49
+ f'{namespace}:{url.name}', request=request)
50
+
51
+ return Response(data or {}, status=status.HTTP_200_OK)
@@ -21,6 +21,7 @@ class AppIndexView(APIView):
21
21
  admin_site = None
22
22
 
23
23
  @extend_schema(
24
+ operation_id="app_index",
24
25
  request=AppIndexSerializer,
25
26
  responses={
26
27
  200: OpenApiResponse(
@@ -1,5 +1,3 @@
1
- # from django.utils.translation import gettext_lazy as _
2
-
3
1
  from rest_framework import status
4
2
  from rest_framework.response import Response
5
3
  from rest_framework.reverse import reverse
@@ -11,7 +9,7 @@ from django_api_admin.serializers import AppListSerializer
11
9
  from django_api_admin.openapi import CommonAPIResponses
12
10
 
13
11
 
14
- class IndexView(APIView):
12
+ class AppListView(APIView):
15
13
  """
16
14
  Return json object that lists all the installed
17
15
  apps that have been registered by the admin site.
@@ -20,6 +18,7 @@ class IndexView(APIView):
20
18
  admin_site = None
21
19
 
22
20
  @extend_schema(
21
+ operation_id="admin_root",
23
22
  responses={
24
23
  200: AppListSerializer,
25
24
  403: CommonAPIResponses.permission_denied(),
@@ -30,7 +29,7 @@ class IndexView(APIView):
30
29
  app_list = self.admin_site.get_app_list(request)
31
30
  # add an url to app_index in every app in app_list
32
31
  for app in app_list:
33
- app['url'] = reverse(f'{self.admin_site.name}:app_list', kwargs={
32
+ app['url'] = reverse(f'{self.admin_site.name}:app_index', kwargs={
34
33
  'app_label': app['app_label']}, request=request)
35
34
  data = {'app_list': app_list}
36
35
  request.current_app = self.admin_site.name
@@ -1,3 +1,15 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Portions of this file are from Django (https://www.djangoproject.com/)
3
+ # Copyright (c) Django Software Foundation and individual contributors.
4
+ # All rights reserved.
5
+ # Licensed under the BSD 3-Clause License.
6
+ #
7
+ # Additional code copyright (c) 2021 Muhammad Salah
8
+ # Licensed under the MIT License
9
+ #
10
+ # This file includes both Django code and your my own contributions.
11
+ # -----------------------------------------------------------------------------
12
+
1
13
  from django.apps import apps
2
14
  from django.utils.translation import gettext_lazy as _
3
15
  from django.core.exceptions import FieldDoesNotExist
@@ -6,7 +18,6 @@ from rest_framework.exceptions import PermissionDenied, ParseError
6
18
  from rest_framework.views import APIView
7
19
  from rest_framework.response import Response
8
20
  from rest_framework import status
9
- from rest_framework.views import APIView
10
21
 
11
22
  from drf_spectacular.utils import extend_schema, OpenApiExample, OpenApiResponse
12
23
 
@@ -1,9 +1,9 @@
1
-
2
- from django.utils.translation import gettext_lazy as _
3
1
  import json
4
2
 
3
+ from django.utils.translation import gettext_lazy as _
5
4
  from django.views.i18n import JSONCatalog
6
5
 
6
+ from rest_framework import status
7
7
  from rest_framework.response import Response
8
8
  from rest_framework.views import APIView
9
9
 
@@ -1,5 +1,3 @@
1
- # from django.utils.translation import gettext_lazy as _
2
-
3
1
  from rest_framework import status
4
2
  from rest_framework.response import Response
5
3
  from rest_framework.views import APIView
@@ -6,7 +6,7 @@ from rest_framework.response import Response
6
6
  from rest_framework.exceptions import PermissionDenied
7
7
  from rest_framework.views import APIView
8
8
 
9
- from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample
9
+ from drf_spectacular.utils import extend_schema, OpenApiResponse
10
10
 
11
11
  from django_api_admin.utils.get_form_fields import get_form_fields
12
12
  from django_api_admin.utils.get_form_config import get_form_config
@@ -48,9 +48,13 @@ class AddView(APIView):
48
48
  serializer = self.serializer_class()
49
49
  data['fields'] = get_form_fields(serializer)
50
50
  data['config'] = get_form_config(self.model_admin)
51
- inlines = get_inlines(request, self.model_admin)
52
- if len(inlines):
53
- data['inlines'] = inlines
51
+
52
+ # Include the model_admin's inlines in the form representation
53
+ if not self.model_admin.is_inline:
54
+ inlines = get_inlines(request, self.model_admin)
55
+ if len(inlines):
56
+ data['inlines'] = inlines
57
+
54
58
  return Response(data, status=status.HTTP_200_OK)
55
59
 
56
60
  def post(self, request):
@@ -58,47 +62,45 @@ class AddView(APIView):
58
62
  Handle POST requests to add a new instance of the model.
59
63
  """
60
64
  with transaction.atomic(using=router.db_for_write(self.model_admin.model)):
61
- # if the user doesn't have added permission respond with permission denied
65
+ # If the user doesn't have add_permission respond with permission denied
62
66
  if not self.model_admin.has_add_permission(request):
63
67
  raise PermissionDenied
64
68
 
65
- # validate data and send
69
+ # Validate the new_object data
66
70
  serializer = self.serializer_class(
67
71
  data=request.data.get('data', {}))
68
72
  if serializer.is_valid():
69
- # create the new object
73
+ # Create the `data` object in the request body used to create the new_object
70
74
  opts = self.model_admin.model._meta
71
75
  new_object = serializer.save()
72
76
  msg = _(
73
77
  f'The {opts.verbose_name} “{str(new_object)}” was added successfully.')
74
78
 
75
- # setup arguments used to log additions
76
- change_object = new_object
77
-
78
- # log addition of the new instance
79
- self.model_admin.log_addition(request, change_object, [{'added': {
79
+ # Log addition of the new instance
80
+ self.model_admin.log_addition(request, new_object, [{'added': {
80
81
  'name': str(new_object._meta.verbose_name),
81
82
  'object': str(new_object),
82
83
  }}])
83
84
 
84
- # process bulk additions
85
+ # Process inline bulk additions
85
86
  created_inlines = []
86
87
  if request.data.get("create_inlines", None):
88
+ # Validate the create_inlines data
87
89
  valid_serializers = validate_bulk_edits(
88
90
  request, self.model_admin, new_object)
89
- # save the inline data in a transaction.
91
+ # Save the inline data (inside a transaction).
90
92
  for inline_serializer in valid_serializers:
91
93
  inline_serializer.save()
92
- # return the data to the user.
94
+ # Return the data to the user.
93
95
  created_inlines = [
94
96
  inline_serializer.data for inline_serializer in valid_serializers]
95
97
 
96
- # return the appropriate 201 response based on the data
98
+ # Return the appropriate 201 response based on the data
97
99
  data = {'data': serializer.data, 'detail': msg}
98
100
  if len(created_inlines):
99
101
  data['created_inlines'] = created_inlines
100
102
 
101
103
  return Response(data, status=status.HTTP_201_CREATED)
102
- else:
103
- # return a 400 response indicating failure
104
- return Response({"errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
104
+
105
+ # return a 400 response indicating failure
106
+ return Response({"errors": serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
@@ -49,9 +49,13 @@ class ChangeView(APIView):
49
49
  data = dict()
50
50
  data['fields'] = get_form_fields(serializer, change=True)
51
51
  data['config'] = get_form_config(self.model_admin)
52
- inlines = get_inlines(request, self.model_admin, obj=obj)
53
- if inlines:
54
- data['inlines'] = inlines
52
+
53
+ # Include the model_admin's inlines in the form representation
54
+ if not self.model_admin.is_inline:
55
+ inlines = get_inlines(request, self.model_admin, obj=obj)
56
+ if inlines:
57
+ data['inlines'] = inlines
58
+
55
59
  return Response(data, status=status.HTTP_200_OK)
56
60
 
57
61
  def update(self, request, object_id):
@@ -14,8 +14,8 @@ class DetailView(APIView):
14
14
  """
15
15
  GET one instance of this model using pk and to_fields.
16
16
  """
17
- permission_classes = []
18
17
  serializer_class = None
18
+ permission_classes = []
19
19
  model_admin = None
20
20
 
21
21
  def get(self, request, object_id):
@@ -48,8 +48,8 @@ class DetailView(APIView):
48
48
  if self.model_admin.view_on_site:
49
49
  model_type = ContentType.objects.get_for_model(
50
50
  model=self.model_admin.model)
51
- data['view_on_site'] = reverse('%s:view_on_site' % self.model_admin.admin_site.name, kwargs={
52
- 'content_type_id': model_type.pk, 'object_id': obj.pk}, request=request)
51
+ data['view_on_site'] = reverse('%s:view_on_site' % self.model_admin.admin_site.name, kwargs={
52
+ 'content_type_id': model_type.pk, 'object_id': obj.pk}, request=request)
53
53
  data['list_url'] = reverse((pattern + 'list') % info, request=request)
54
54
  data['history_url'] = reverse(
55
55
  (pattern + 'history') % info, kwargs={'object_id': data['pk']}, request=request)
@@ -8,15 +8,14 @@ from rest_framework.exceptions import PermissionDenied
8
8
  from django_api_admin.models import LogEntry
9
9
  from django_api_admin.utils.quote import unquote
10
10
  from django_api_admin.utils.get_content_type_for_model import get_content_type_for_model
11
- from rest_framework.views import APIView
12
11
 
13
12
 
14
13
  class HistoryView(APIView):
15
14
  """
16
15
  History of actions that happened to this object.
17
16
  """
18
- permission_classes = []
19
17
  serializer_class = None
18
+ permission_classes = []
20
19
  model_admin = None
21
20
 
22
21
  def get(self, request, object_id):
@@ -1,12 +1,8 @@
1
- from django.utils.translation import gettext_lazy as _
2
-
3
1
  from rest_framework import status
4
2
  from rest_framework.views import APIView
5
3
  from rest_framework.reverse import reverse
6
4
  from rest_framework.response import Response
7
5
 
8
- from rest_framework.views import APIView
9
-
10
6
 
11
7
  class ListView(APIView):
12
8
  """
@@ -1,7 +1,18 @@
1
+ # -----------------------------------------------------------------------------
2
+ # Portions of this file are from Django (https://www.djangoproject.com/)
3
+ # Copyright (c) Django Software Foundation and individual contributors.
4
+ # All rights reserved.
5
+ # Licensed under the BSD 3-Clause License.
6
+ #
7
+ # Additional code copyright (c) 2021 Muhammad Salah
8
+ # Licensed under the MIT License
9
+ #
10
+ # This file includes both Django code and your my own contributions.
11
+ # -----------------------------------------------------------------------------
12
+
1
13
  import copy
2
14
 
3
15
  from django.contrib.auth import get_permission_codename
4
- from django.utils.translation import gettext as _
5
16
 
6
17
  from rest_framework.serializers import ModelSerializer
7
18
 
@@ -85,7 +96,7 @@ class BaseAPIModelAdmin:
85
96
 
86
97
  # dynamically construct a model serializer
87
98
  self.serializer_class = type(data['parent_class'])(
88
- f'{self.model.__name__}AdminSerializer',
99
+ f'{'Inline' if self.is_inline else ''}{self.model.__name__}AdminSerializer',
89
100
  (data['parent_class'],),
90
101
  attrs
91
102
  )
@@ -229,8 +240,8 @@ class BaseAPIModelAdmin:
229
240
 
230
241
  defaults = {
231
242
  'serializer_class': self.get_serializer_class(),
232
- 'permission_classes': self.admin_site.default_permission_classes,
233
- 'authentication_classes': self.admin_site.authentication_classes,
243
+ 'permission_classes': self.admin_site.get_permission_classes(),
244
+ 'authentication_classes': self.admin_site.get_authentication_classes(),
234
245
  'model_admin': self,
235
246
  }
236
247
  return ListView.as_view(**defaults)
@@ -240,8 +251,8 @@ class BaseAPIModelAdmin:
240
251
 
241
252
  defaults = {
242
253
  'serializer_class': self.get_serializer_class(),
243
- 'permission_classes': self.admin_site.default_permission_classes,
244
- 'authentication_classes': self.admin_site.authentication_classes,
254
+ 'permission_classes': self.admin_site.get_permission_classes(),
255
+ 'authentication_classes': self.admin_site.get_authentication_classes(),
245
256
  'model_admin': self
246
257
  }
247
258
  return DetailView.as_view(**defaults)
@@ -251,8 +262,8 @@ class BaseAPIModelAdmin:
251
262
 
252
263
  defaults = {
253
264
  'serializer_class': self.get_serializer_class(),
254
- 'permission_classes': self.admin_site.default_permission_classes,
255
- 'authentication_classes': self.admin_site.authentication_classes,
265
+ 'permission_classes': self.admin_site.get_permission_classes(),
266
+ 'authentication_classes': self.admin_site.get_authentication_classes(),
256
267
  'model_admin': self,
257
268
  }
258
269
  return AddView.as_view(**defaults)
@@ -262,8 +273,8 @@ class BaseAPIModelAdmin:
262
273
 
263
274
  defaults = {
264
275
  'serializer_class': self.get_serializer_class(),
265
- 'permission_classes': self.admin_site.default_permission_classes,
266
- 'authentication_classes': self.admin_site.authentication_classes,
276
+ 'permission_classes': self.admin_site.get_permission_classes(),
277
+ 'authentication_classes': self.admin_site.get_authentication_classes(),
267
278
  'model_admin': self,
268
279
  }
269
280
  return ChangeView.as_view(**defaults)
@@ -272,8 +283,8 @@ class BaseAPIModelAdmin:
272
283
  from django_api_admin.admin_views.model_admin_views.delete import DeleteView
273
284
 
274
285
  defaults = {
275
- 'permission_classes': self.admin_site.default_permission_classes,
276
- 'authentication_classes': self.admin_site.authentication_classes,
286
+ 'permission_classes': self.admin_site.get_permission_classes(),
287
+ 'authentication_classes': self.admin_site.get_authentication_classes(),
277
288
  'model_admin': self
278
289
  }
279
290
  return DeleteView.as_view(**defaults)