django-api-admin 1.2.0__tar.gz → 1.2.2__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 (92) hide show
  1. {django_api_admin-1.2.0 → django_api_admin-1.2.2}/PKG-INFO +19 -5
  2. {django_api_admin-1.2.0 → django_api_admin-1.2.2}/README.md +18 -4
  3. django_api_admin-1.2.2/django_api_admin/__init__.py +47 -0
  4. django_api_admin-1.2.2/django_api_admin/actions.py +40 -0
  5. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/__init__.py +0 -0
  6. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/admin_api_root.py +23 -0
  7. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/admin_log.py +83 -0
  8. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/app_index.py +63 -0
  9. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/autocomplete.py +155 -0
  10. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/index.py +38 -0
  11. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/language_catalog.py +98 -0
  12. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/obtain_token.py +95 -0
  13. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/password_change.py +77 -0
  14. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/site_context.py +29 -0
  15. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/token_refresh.py +7 -0
  16. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/user_information.py +40 -0
  17. django_api_admin-1.2.2/django_api_admin/admin_views/admin_site_views/view_on_site.py +122 -0
  18. django_api_admin-1.2.2/django_api_admin/admin_views/model_admin_views/__init__.py +0 -0
  19. django_api_admin-1.2.2/django_api_admin/admin_views/model_admin_views/add.py +104 -0
  20. django_api_admin-1.2.2/django_api_admin/admin_views/model_admin_views/change.py +208 -0
  21. django_api_admin-1.2.2/django_api_admin/admin_views/model_admin_views/changelist.py +176 -0
  22. django_api_admin-1.2.2/django_api_admin/admin_views/model_admin_views/delete.py +104 -0
  23. django_api_admin-1.2.2/django_api_admin/admin_views/model_admin_views/detail.py +60 -0
  24. django_api_admin-1.2.2/django_api_admin/admin_views/model_admin_views/handle_action.py +105 -0
  25. django_api_admin-1.2.2/django_api_admin/admin_views/model_admin_views/history.py +52 -0
  26. django_api_admin-1.2.2/django_api_admin/admin_views/model_admin_views/list.py +36 -0
  27. django_api_admin-1.2.2/django_api_admin/admins/__init__.py +0 -0
  28. django_api_admin-1.2.2/django_api_admin/admins/base_admin.py +284 -0
  29. django_api_admin-1.2.2/django_api_admin/admins/inline_admin.py +87 -0
  30. django_api_admin-1.2.2/django_api_admin/admins/model_admin.py +593 -0
  31. django_api_admin-1.2.2/django_api_admin/apps.py +27 -0
  32. django_api_admin-1.2.2/django_api_admin/changelist.py +490 -0
  33. django_api_admin-1.2.2/django_api_admin/checks.py +1264 -0
  34. django_api_admin-1.2.2/django_api_admin/constants/__init__.py +0 -0
  35. django_api_admin-1.2.2/django_api_admin/constants/field_attributes.py +82 -0
  36. django_api_admin-1.2.2/django_api_admin/constants/vars.py +12 -0
  37. django_api_admin-1.2.2/django_api_admin/declarations/__init__.py +0 -0
  38. django_api_admin-1.2.2/django_api_admin/declarations/functions.py +305 -0
  39. django_api_admin-1.2.2/django_api_admin/decorators.py +108 -0
  40. django_api_admin-1.2.2/django_api_admin/exceptions.py +31 -0
  41. django_api_admin-1.2.2/django_api_admin/filters.py +554 -0
  42. django_api_admin-1.2.2/django_api_admin/hooks.py +67 -0
  43. django_api_admin-1.2.2/django_api_admin/migrations/0001_initial.py +42 -0
  44. django_api_admin-1.2.2/django_api_admin/migrations/__init__.py +0 -0
  45. django_api_admin-1.2.2/django_api_admin/models.py +194 -0
  46. django_api_admin-1.2.2/django_api_admin/openapi.py +303 -0
  47. django_api_admin-1.2.2/django_api_admin/options.py +287 -0
  48. django_api_admin-1.2.2/django_api_admin/pagination.py +24 -0
  49. django_api_admin-1.2.2/django_api_admin/permissions.py +10 -0
  50. django_api_admin-1.2.2/django_api_admin/serializers.py +399 -0
  51. django_api_admin-1.2.2/django_api_admin/sites.py +510 -0
  52. django_api_admin-1.2.2/django_api_admin/utils/__init__.py +0 -0
  53. django_api_admin-1.2.2/django_api_admin/utils/_get_non_gfk_field.py +30 -0
  54. django_api_admin-1.2.2/django_api_admin/utils/diff_helper.py +46 -0
  55. django_api_admin-1.2.2/django_api_admin/utils/flatten.py +11 -0
  56. django_api_admin-1.2.2/django_api_admin/utils/force_login.py +14 -0
  57. django_api_admin-1.2.2/django_api_admin/utils/get_content_type_for_model.py +6 -0
  58. django_api_admin-1.2.2/django_api_admin/utils/get_deleted_objects.py +67 -0
  59. django_api_admin-1.2.2/django_api_admin/utils/get_field_attributes.py +54 -0
  60. django_api_admin-1.2.2/django_api_admin/utils/get_fields_from_path.py +22 -0
  61. django_api_admin-1.2.2/django_api_admin/utils/get_form_config.py +13 -0
  62. django_api_admin-1.2.2/django_api_admin/utils/get_form_fields.py +46 -0
  63. django_api_admin-1.2.2/django_api_admin/utils/get_inline_by_field_name.py +12 -0
  64. django_api_admin-1.2.2/django_api_admin/utils/get_inlines.py +51 -0
  65. django_api_admin-1.2.2/django_api_admin/utils/get_model_from_relation.py +8 -0
  66. django_api_admin-1.2.2/django_api_admin/utils/get_related_name.py +10 -0
  67. django_api_admin-1.2.2/django_api_admin/utils/label_for_field.py +70 -0
  68. django_api_admin-1.2.2/django_api_admin/utils/lookup_field.py +29 -0
  69. django_api_admin-1.2.2/django_api_admin/utils/lookup_spawns_duplicates.py +28 -0
  70. django_api_admin-1.2.2/django_api_admin/utils/model_format_dict.py +17 -0
  71. django_api_admin-1.2.2/django_api_admin/utils/model_ngettext.py +39 -0
  72. django_api_admin-1.2.2/django_api_admin/utils/nested_objects.py +71 -0
  73. django_api_admin-1.2.2/django_api_admin/utils/prepare_lookup_value.py +11 -0
  74. django_api_admin-1.2.2/django_api_admin/utils/quote.py +22 -0
  75. django_api_admin-1.2.2/django_api_admin/utils/remove_field.py +12 -0
  76. django_api_admin-1.2.2/django_api_admin/utils/reverse_field_path.py +34 -0
  77. django_api_admin-1.2.2/django_api_admin/utils/url_params_from_lookup_dict.py +18 -0
  78. django_api_admin-1.2.2/django_api_admin/utils/validate_bulk_edits.py +105 -0
  79. django_api_admin-1.2.2/django_api_admin/utils/validate_inline_field_names.py +25 -0
  80. django_api_admin-1.2.2/django_api_admin/views/__init__.py +0 -0
  81. django_api_admin-1.2.2/django_api_admin/views/admin_views.py +677 -0
  82. django_api_admin-1.2.2/django_api_admin/views/site_views.py +251 -0
  83. {django_api_admin-1.2.0 → django_api_admin-1.2.2}/django_api_admin.egg-info/PKG-INFO +19 -5
  84. django_api_admin-1.2.2/django_api_admin.egg-info/SOURCES.txt +88 -0
  85. django_api_admin-1.2.2/django_api_admin.egg-info/top_level.txt +2 -0
  86. {django_api_admin-1.2.0 → django_api_admin-1.2.2}/pyproject.toml +4 -2
  87. django_api_admin-1.2.0/django_api_admin.egg-info/SOURCES.txt +0 -8
  88. django_api_admin-1.2.0/django_api_admin.egg-info/top_level.txt +0 -1
  89. {django_api_admin-1.2.0 → django_api_admin-1.2.2}/LICENSE +0 -0
  90. {django_api_admin-1.2.0 → django_api_admin-1.2.2}/django_api_admin.egg-info/dependency_links.txt +0 -0
  91. {django_api_admin-1.2.0 → django_api_admin-1.2.2}/django_api_admin.egg-info/requires.txt +0 -0
  92. {django_api_admin-1.2.0 → django_api_admin-1.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: django-api-admin
3
- Version: 1.2.0
3
+ Version: 1.2.2
4
4
  Summary: A RESTful API implementation of django.contrib.admin, designed for writing custom frontends.
5
5
  Author-email: Muhammad Salah <msbizzacc0unt@outlook.com>
6
6
  License: MIT License
@@ -69,9 +69,9 @@ Requires-Dist: django-cors-headers; extra == "dev"
69
69
  <!-- <br /> -->
70
70
  <!-- <a href="https://github.com/othneildrew/Best-README-Template">View Demo</a>
71
71
  &middot; -->
72
- <a href="https://github.com/othneildrew/Best-README-Template/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
72
+ <a href="https://github.com/demon-bixia/django-api-admin/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
73
73
  &middot;
74
- <a href="https://github.com/othneildrew/Best-README-Template/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
74
+ <a href="https://github.com/demon-bixia/django-api-admin/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
75
75
  </p>
76
76
  </div>
77
77
 
@@ -204,6 +204,16 @@ This guide will walk you through the steps to integrate `django-api-admin` into
204
204
  )
205
205
  CORS_ALLOW_CREDENTIALS = True
206
206
  ```
207
+ 5. **Add the modify_schema hook** used to tag paths in the openapi schema
208
+ ```py
209
+ # settings.py
210
+ SPECTACULAR_SETTINGS = {
211
+ "POSTPROCESSING_HOOKS": [
212
+ 'drf_spectacular.hooks.postprocess_schema_enums',
213
+ 'django_api_admin.hooks.modify_schema'
214
+ ]
215
+ }
216
+ ```
207
217
 
208
218
  Thats it you are now ready to register your models and implement your django admin frontend!
209
219
 
@@ -249,8 +259,11 @@ This section provides a simple example on how to use django-api-admin. If you're
249
259
  from django.urls import path
250
260
  from django_api_admin.sites import site
251
261
 
262
+ # the admin site needs to know the name of the url prefix in this case "admin/"
263
+ # the default is just the admin site's name which is "admin" + "/"
264
+ # for the default admin site
252
265
  urlpatterns = [
253
- path('api_admin/', site.urls),
266
+ path('admin/', site.urls),
254
267
  ]
255
268
  ```
256
269
 
@@ -333,6 +346,7 @@ This section is dedicated to recognizing the valuable resources and contribution
333
346
  * [Simple JWT](https://github.com/jazzband/djangorestframework-simplejwt/tree/master)
334
347
  * [Django Cors Headers](https://github.com/adamchainz/django-cors-headers)
335
348
  * [DRF Spectacular](https://github.com/tfranzel/drf-spectacular)
349
+ * [Django Restful Admin](https://github.com/amirasaran/django-restful-admin)
336
350
  * [Best README Template](https://github.com/othneildrew/Best-README-Template)
337
351
  * [QODO AI](https://www.qodo.ai/)
338
352
 
@@ -342,7 +356,7 @@ This section is dedicated to recognizing the valuable resources and contribution
342
356
 
343
357
  <!-- MARKDOWN LINKS & IMAGES -->
344
358
  <!-- 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
359
+ [contributors-shield]: https://img.shields.io/github/contributors/demon-bixia/django-api-admin.svg?style=for-the-badge
346
360
  [contributors-url]: https://github.com/demon-bixia/django-api-admin/graphs/contributors
347
361
 
348
362
  [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
 
@@ -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
 
@@ -293,6 +306,7 @@ 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
311
  * [QODO AI](https://www.qodo.ai/)
298
312
 
@@ -302,7 +316,7 @@ This section is dedicated to recognizing the valuable resources and contribution
302
316
 
303
317
  <!-- MARKDOWN LINKS & IMAGES -->
304
318
  <!-- 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
319
+ [contributors-shield]: https://img.shields.io/github/contributors/demon-bixia/django-api-admin.svg?style=for-the-badge
306
320
  [contributors-url]: https://github.com/demon-bixia/django-api-admin/graphs/contributors
307
321
 
308
322
  [forks-shield]: https://img.shields.io/github/forks/demon-bixia/django-api-admin.svg?style=for-the-badge
@@ -0,0 +1,47 @@
1
+ from django.utils.module_loading import autodiscover_modules
2
+
3
+ from django_api_admin.decorators import action, display, register
4
+ from django_api_admin.filters import (
5
+ AllValuesFieldListFilter,
6
+ BooleanFieldListFilter,
7
+ ChoicesFieldListFilter,
8
+ DateFieldListFilter,
9
+ EmptyFieldListFilter,
10
+ FieldListFilter,
11
+ ListFilter,
12
+ RelatedFieldListFilter,
13
+ RelatedOnlyFieldListFilter,
14
+ SimpleListFilter,
15
+ )
16
+ from django_api_admin.constants.vars import HORIZONTAL, VERTICAL
17
+ from django_api_admin.admins.model_admin import APIModelAdmin
18
+ from django_api_admin.admins.inline_admin import StackedInlineAPI, TabularInlineAPI
19
+ from django_api_admin.sites import APIAdminSite, site
20
+
21
+ __all__ = [
22
+ "action",
23
+ "display",
24
+ "register",
25
+ "APIModelAdmin",
26
+ "HORIZONTAL",
27
+ "VERTICAL",
28
+ "StackedInlineAPI",
29
+ "TabularInlineAPI",
30
+ "APIAdminSite",
31
+ "site",
32
+ "ListFilter",
33
+ "SimpleListFilter",
34
+ "FieldListFilter",
35
+ "BooleanFieldListFilter",
36
+ "RelatedFieldListFilter",
37
+ "ChoicesFieldListFilter",
38
+ "DateFieldListFilter",
39
+ "AllValuesFieldListFilter",
40
+ "EmptyFieldListFilter",
41
+ "RelatedOnlyFieldListFilter",
42
+ "autodiscover",
43
+ ]
44
+
45
+
46
+ def autodiscover():
47
+ autodiscover_modules("admin", register_to=site)
@@ -0,0 +1,40 @@
1
+ from django.utils.translation import gettext_lazy, gettext as _
2
+
3
+ from rest_framework import status
4
+ from rest_framework.exceptions import PermissionDenied
5
+ from rest_framework.response import Response
6
+
7
+ from django_api_admin.utils.model_ngettext import model_ngettext
8
+ from django_api_admin.utils.get_deleted_objects import get_deleted_objects
9
+ from django_api_admin.decorators import action
10
+
11
+
12
+ @action(
13
+ permissions=['delete'],
14
+ description=gettext_lazy('Delete selected %(verbose_name_plural)s')
15
+ )
16
+ def delete_selected(modeladmin, request, queryset):
17
+ """
18
+ default api_admin action deletes the selected objects
19
+ no confirmation page
20
+ """
21
+ _deletable_objects, _model_count, perms_needed, _protected = get_deleted_objects(
22
+ queryset, request, modeladmin.admin_site)
23
+
24
+ # check the permissions
25
+ if perms_needed:
26
+ objects_name = model_ngettext(queryset)
27
+ msg = _("Cannot delete %(name)s") % {"name": objects_name}
28
+ raise PermissionDenied(detail=msg)
29
+
30
+ # log the deletion of all the objects inside the queryset
31
+ n = queryset.count()
32
+ if n:
33
+ for obj in queryset:
34
+ modeladmin.log_deletion(request, obj, str(obj))
35
+
36
+ # delete the queryset
37
+ queryset.delete()
38
+ msg = _("Successfully deleted %s %s.") % (
39
+ n, model_ngettext(modeladmin.opts, n))
40
+ return Response({'detail': msg}, status=status.HTTP_200_OK)
@@ -0,0 +1,23 @@
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
+
9
+ class AdminAPIRootView(APIView):
10
+ """
11
+ A list of all root urls in django_api_admin
12
+ """
13
+ root_urls = None
14
+
15
+ def get(self, request, *args, **kwargs):
16
+ namespace = request.resolver_match.namespace
17
+ data = dict()
18
+
19
+ for url in self.root_urls:
20
+ data[url.name] = reverse(
21
+ namespace + ':' + url.name, args=args, kwargs=kwargs, request=request)
22
+
23
+ return Response(data or {}, status=status.HTTP_200_OK)
@@ -0,0 +1,83 @@
1
+ import json
2
+
3
+ from django.utils.translation import gettext_lazy as _
4
+
5
+ from rest_framework import status
6
+ from rest_framework.response import Response
7
+ from rest_framework.views import APIView
8
+
9
+ from drf_spectacular.utils import extend_schema, OpenApiResponse
10
+
11
+ from django_api_admin.models import LogEntry
12
+ from django_api_admin.openapi import CommonAPIResponses
13
+ from django_api_admin.serializers import LogEntrySerializer, AdminLogRequestSerializer
14
+
15
+
16
+ class AdminLogView(APIView):
17
+ """
18
+ Returns a list of actions that were preformed using django admin.
19
+ """
20
+ serializer_class = None
21
+ pagination_class = None
22
+ permission_classes = []
23
+ ordering_fields = ['action_time', '-action_time']
24
+ admin_site = None
25
+
26
+ @extend_schema(
27
+ methods=['GET'],
28
+ parameters=[AdminLogRequestSerializer],
29
+ responses={
30
+ 200: OpenApiResponse(
31
+ response=LogEntrySerializer(many=True),
32
+ description=_('Successfully retrieved admin log entries')
33
+ ),
34
+ 401: CommonAPIResponses.unauthorized(),
35
+ 403: CommonAPIResponses.permission_denied(),
36
+ },
37
+ description=_('Retrieve a list of admin log entries'),
38
+ tags=['admin-log']
39
+ )
40
+ def get(self, request):
41
+ queryset = LogEntry.objects.all()
42
+
43
+ # order the queryset
44
+ try:
45
+ ordering = self.request.query_params.get('o')
46
+ if ordering is not None:
47
+ if ordering not in self.ordering_fields:
48
+ raise KeyError
49
+ queryset = queryset.order_by(ordering)
50
+ except:
51
+ return Response({'detail': _('Wrong ordering field set.')}, status=status.HTTP_400_BAD_REQUEST)
52
+
53
+ # filter the queryset.
54
+ try:
55
+ object_id = self.request.query_params.get('object_id')
56
+ if object_id is not None:
57
+ queryset = queryset.filter(object_id=object_id)
58
+ except:
59
+ return Response({'detail': _('Bad filters.')}, status=status.HTTP_400_BAD_REQUEST)
60
+
61
+ # paginate queryset.
62
+ paginator = self.pagination_class()
63
+ page = paginator.paginate_queryset(queryset, request, view=self)
64
+
65
+ # serialize queryset.
66
+ serializer = self.serializer_class(page, many=True)
67
+
68
+ return Response({
69
+ 'action_list': self.serialize_messages(serializer.data),
70
+ 'config': self.get_config(page, queryset)},
71
+ status=status.HTTP_200_OK)
72
+
73
+ def serialize_messages(self, data):
74
+ for idx, item in enumerate(data, start=0):
75
+ data[idx]['change_message'] = json.loads(
76
+ item['change_message'] or '[]')
77
+ return data
78
+
79
+ def get_config(self, page, queryset):
80
+ return {
81
+ 'result_count': len(page),
82
+ 'full_result_count': queryset.count(),
83
+ }
@@ -0,0 +1,63 @@
1
+ from django.utils.translation import gettext_lazy as _
2
+
3
+ from rest_framework.response import Response
4
+ from rest_framework import status
5
+ from rest_framework.exceptions import ParseError
6
+
7
+ from rest_framework.views import APIView
8
+
9
+ from drf_spectacular.utils import extend_schema, OpenApiResponse
10
+
11
+ from django_api_admin.serializers import AppIndexSerializer, AppSerializer
12
+ from django_api_admin.openapi import CommonAPIResponses
13
+
14
+
15
+ class AppIndexView(APIView):
16
+ """
17
+ Lists models inside a given app.
18
+ """
19
+ serializer_class = AppIndexSerializer
20
+ permission_classes = []
21
+ admin_site = None
22
+
23
+ @extend_schema(
24
+ operation_id="app_index",
25
+ request=AppIndexSerializer,
26
+ responses={
27
+ 200: OpenApiResponse(
28
+ response=AppSerializer,
29
+ description=_(
30
+ "Successfully constructed the list of registered models")
31
+ ),
32
+ 403: CommonAPIResponses.permission_denied(),
33
+ 401: CommonAPIResponses.unauthorized()
34
+ }
35
+ )
36
+ def get(self, request, app_label):
37
+ serializer = self.get_serializer(app_label)
38
+ if not serializer.is_valid():
39
+ raise ParseError({"detail": _("invalid app_label")})
40
+
41
+ app_dict = self.admin_site._build_app_dict(request, app_label)
42
+
43
+ if not app_dict:
44
+ return Response({'detail': _('The requested admin page does not exist.')},
45
+ status=status.HTTP_404_NOT_FOUND)
46
+
47
+ # Sort the models alphabetically within each app.
48
+ app_dict['models'].sort(key=lambda x: x['name'])
49
+
50
+ data = {
51
+ 'app_label': app_label,
52
+ 'app': app_dict,
53
+ }
54
+ return Response(data, status=status.HTTP_200_OK)
55
+
56
+ def get_serializer(self, app_label):
57
+ registered_app_labels = {
58
+ model._meta.app_label for model in self.admin_site._registry.keys()
59
+ }
60
+ return AppIndexSerializer(
61
+ data={"app_label": app_label},
62
+ context={'registered_app_labels': registered_app_labels}
63
+ )
@@ -0,0 +1,155 @@
1
+ from django.apps import apps
2
+ from django.utils.translation import gettext_lazy as _
3
+ from django.core.exceptions import FieldDoesNotExist
4
+
5
+ from rest_framework.exceptions import PermissionDenied, ParseError
6
+ from rest_framework.views import APIView
7
+ from rest_framework.response import Response
8
+ from rest_framework import status
9
+ from rest_framework.views import APIView
10
+
11
+ from drf_spectacular.utils import extend_schema, OpenApiExample, OpenApiResponse
12
+
13
+ from django_api_admin.serializers import AutoCompleteSerializer
14
+ from django_api_admin.openapi import CommonAPIResponses
15
+
16
+
17
+ class AutoCompleteView(APIView):
18
+ """
19
+ API view for handling autocomplete functionality in admin fields.
20
+ """
21
+ permission_classes = []
22
+ admin_site = None
23
+
24
+ @extend_schema(
25
+ parameters=[AutoCompleteSerializer],
26
+ responses={
27
+ 200: OpenApiResponse(
28
+ description=_("Successful autocomplete response"),
29
+ response=AutoCompleteSerializer,
30
+ examples=[
31
+ OpenApiExample(
32
+ name=_("Success Response"),
33
+ summary=_(
34
+ "Example of a successful autocomplete response"),
35
+ description="Returns matching records based on the search term",
36
+ value=[{
37
+ "id": 1,
38
+ "name": "Muhammad",
39
+ "age": 60,
40
+ "is_vip": True,
41
+ "date_joined": "2025-02-02T23:09:31.994853Z",
42
+ "title": None,
43
+ "user": 1,
44
+ "publisher": [1],
45
+ "pk": 1
46
+ }],
47
+ status_codes=["200"],
48
+ )
49
+ ]
50
+ ),
51
+ 403: CommonAPIResponses.permission_denied(),
52
+ 401: CommonAPIResponses.unauthorized(),
53
+ },
54
+ description=_(
55
+ "Endpoint for autocomplete functionality on model fields")
56
+ )
57
+ def get(self, request):
58
+ """
59
+ Process the request to extract search parameters,
60
+ validates user permissions, retrieves the relevant queryset,
61
+ paginates the results, and returns them as a JSON response.
62
+ """
63
+ (
64
+ self.term,
65
+ self.model_admin,
66
+ self.source_field,
67
+ to_field_name,
68
+ ) = self.process_request(request)
69
+
70
+ if not self.has_perm(request):
71
+ raise PermissionDenied
72
+
73
+ self.queryset = self.get_queryset()
74
+ page = self.admin_site.paginate_queryset(
75
+ self.queryset, request, view=self)
76
+
77
+ # serialize data
78
+ serializer_class = self.model_admin.get_serializer_class()
79
+ serializer = serializer_class(page, many=True)
80
+ data = serializer.data
81
+
82
+ return Response(
83
+ data,
84
+ status=status.HTTP_200_OK
85
+ )
86
+
87
+ def get_queryset(self):
88
+ """Return queryset based on model_admin.get_search_results()."""
89
+ qs = self.model_admin.get_queryset()
90
+ qs = qs.complex_filter(self.source_field.get_limit_choices_to())
91
+ qs, search_use_distinct = self.model_admin.get_search_results(
92
+ qs, self.term)
93
+ if search_use_distinct:
94
+ qs = qs.distinct()
95
+ return qs
96
+
97
+ def process_request(self, request):
98
+ """
99
+ Validate request integrity, extract and return request parameters.
100
+
101
+ Since the subsequent view permission check requires the target model
102
+ admin, which is determined here, raise PermissionDenied if the
103
+ requested app, model or field are malformed.
104
+
105
+ Raise Http404 if the target model admin is not configured properly with
106
+ search_fields.
107
+ """
108
+ term = request.GET.get("term", "")
109
+
110
+ try:
111
+ app_label = request.GET["app_label"]
112
+ model_name = request.GET["model_name"]
113
+ field_name = request.GET["field_name"]
114
+ except KeyError:
115
+ raise ParseError(
116
+ {'detail': _('missing values app_label, model_name, and field_name')})
117
+
118
+ # Retrieve objects from parameters.
119
+ try:
120
+ source_model = apps.get_model(app_label, model_name)
121
+ except LookupError:
122
+ raise ParseError({'detail': _('source model not found')})
123
+ try:
124
+ source_field = source_model._meta.get_field(field_name)
125
+ except FieldDoesNotExist:
126
+ raise ParseError(
127
+ {f'detail': _(f'source field not found in source model {source_model._meta.verbose_name}')})
128
+ try:
129
+ remote_model = source_field.remote_field.model
130
+ except AttributeError:
131
+ raise ParseError(
132
+ {'detail': _(f'unable to locate the related model using source field {source_field.name}')})
133
+ try:
134
+ model_admin = self.admin_site._registry[remote_model]
135
+ except KeyError:
136
+ raise ParseError(
137
+ {'detail': _('the remote model is not registered in the admin')})
138
+
139
+ # Validate suitability of objects.
140
+ if not getattr(model_admin, "search_fields"):
141
+ raise ParseError(_('%s must have search_fields for the autocomplete_view."') % type(
142
+ model_admin).__qualname__)
143
+
144
+ to_field_name = getattr(
145
+ source_field.remote_field, "field_name", remote_model._meta.pk.attname
146
+ )
147
+ to_field_name = remote_model._meta.get_field(to_field_name).attname
148
+ if not model_admin.to_field_allowed(to_field_name):
149
+ raise PermissionDenied
150
+
151
+ return term, model_admin, source_field, to_field_name
152
+
153
+ def has_perm(self, request):
154
+ """Check if user has permission to access the related model."""
155
+ return self.model_admin.has_view_permission(request)
@@ -0,0 +1,38 @@
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.reverse import reverse
6
+ from rest_framework.views import APIView
7
+
8
+ from drf_spectacular.utils import extend_schema
9
+
10
+ from django_api_admin.serializers import AppListSerializer
11
+ from django_api_admin.openapi import CommonAPIResponses
12
+
13
+
14
+ class IndexView(APIView):
15
+ """
16
+ Return json object that lists all the installed
17
+ apps that have been registered by the admin site.
18
+ """
19
+ permission_classes = []
20
+ admin_site = None
21
+
22
+ @extend_schema(
23
+ operation_id="admin_root",
24
+ responses={
25
+ 200: AppListSerializer,
26
+ 403: CommonAPIResponses.permission_denied(),
27
+ 401: CommonAPIResponses.unauthorized()
28
+ },
29
+ )
30
+ def get(self, request):
31
+ app_list = self.admin_site.get_app_list(request)
32
+ # add an url to app_index in every app in app_list
33
+ for app in app_list:
34
+ app['url'] = reverse(f'{self.admin_site.name}:app_list', kwargs={
35
+ 'app_label': app['app_label']}, request=request)
36
+ data = {'app_list': app_list}
37
+ request.current_app = self.admin_site.name
38
+ return Response(data, status=status.HTTP_200_OK)
@@ -0,0 +1,98 @@
1
+
2
+ from django.utils.translation import gettext_lazy as _
3
+ import json
4
+
5
+ from django.views.i18n import JSONCatalog
6
+
7
+ from rest_framework.response import Response
8
+ from rest_framework.views import APIView
9
+
10
+ from drf_spectacular.utils import extend_schema, OpenApiResponse, OpenApiExample
11
+
12
+ from django_api_admin.serializers import LanguageCatalogSerializer
13
+ from django_api_admin.openapi import CommonAPIResponses
14
+
15
+
16
+ class LanguageCatalogView(APIView):
17
+ """
18
+ Returns json object with i18n translation catalog
19
+ to be used by a client site javascript library
20
+ """
21
+ permission_classes = []
22
+ admin_site = None
23
+
24
+ @extend_schema(
25
+ responses={
26
+ 200: OpenApiResponse(
27
+ response=LanguageCatalogSerializer,
28
+ description=_("Successful retrieval of the language catalog."),
29
+ examples=[
30
+ OpenApiExample(
31
+ name=_("Success Response"),
32
+ summary=_(
33
+ "Example of a successful language catalog request"),
34
+ description=_(
35
+ "return the translation string used in this app"),
36
+ value={
37
+ "catalog": {
38
+ "AM": "ص",
39
+ "PM": "م",
40
+ "January": "يناير",
41
+ "February": "فبراير"
42
+ },
43
+ "formats": {
44
+ "DATE_FORMAT": "j F، Y",
45
+ "DATETIME_FORMAT": "N j, Y, P",
46
+ "TIME_FORMAT": "g:i A",
47
+ "YEAR_MONTH_FORMAT": "F Y",
48
+ "MONTH_DAY_FORMAT": "j F",
49
+ "SHORT_DATE_FORMAT": "d/m/Y",
50
+ "SHORT_DATETIME_FORMAT": "m/d/Y P",
51
+ "FIRST_DAY_OF_WEEK": 0,
52
+ "DECIMAL_SEPARATOR": ",",
53
+ "THOUSAND_SEPARATOR": ".",
54
+ "NUMBER_GROUPING": 0,
55
+ "DATE_INPUT_FORMATS": [
56
+ "%Y-%m-%d",
57
+ "%m/%d/%Y",
58
+ "%m/%d/%y",
59
+ "%b %d %Y",
60
+ "%b %d, %Y",
61
+ "%d %b %Y",
62
+ "%d %b, %Y",
63
+ "%B %d %Y",
64
+ "%B %d, %Y",
65
+ "%d %B %Y",
66
+ "%d %B, %Y"
67
+ ],
68
+ "TIME_INPUT_FORMATS": [
69
+ "%H:%M:%S",
70
+ "%H:%M:%S.%f",
71
+ "%H:%M"
72
+ ],
73
+ "DATETIME_INPUT_FORMATS": [
74
+ "%Y-%m-%d %H:%M:%S",
75
+ "%Y-%m-%d %H:%M:%S.%f",
76
+ "%Y-%m-%d %H:%M",
77
+ "%m/%d/%Y %H:%M:%S",
78
+ "%m/%d/%Y %H:%M:%S.%f",
79
+ "%m/%d/%Y %H:%M",
80
+ "%m/%d/%y %H:%M:%S",
81
+ "%m/%d/%y %H:%M:%S.%f",
82
+ "%m/%d/%y %H:%M"
83
+ ]
84
+ },
85
+ "plural": "n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5",
86
+ },
87
+ status_codes=["200"],
88
+ )
89
+ ]
90
+ ),
91
+ 403: CommonAPIResponses.permission_denied(),
92
+ 401: CommonAPIResponses.unauthorized(),
93
+ }
94
+ )
95
+ def get(self, request):
96
+ response = JSONCatalog.as_view(
97
+ packages=['django_api_admin'], domain='django')(request)
98
+ return Response(json.loads(response.content), status=response.status_code)