django-content-studio 1.0.0b5__py3-none-any.whl

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 (49) hide show
  1. content_studio/__init__.py +7 -0
  2. content_studio/admin.py +307 -0
  3. content_studio/apps.py +100 -0
  4. content_studio/dashboard/__init__.py +64 -0
  5. content_studio/dashboard/activity_log.py +35 -0
  6. content_studio/filters.py +124 -0
  7. content_studio/form.py +178 -0
  8. content_studio/formats.py +59 -0
  9. content_studio/login_backends/__init__.py +21 -0
  10. content_studio/login_backends/username_password.py +82 -0
  11. content_studio/media_library/serializers.py +25 -0
  12. content_studio/media_library/viewsets.py +132 -0
  13. content_studio/models.py +73 -0
  14. content_studio/paginators.py +20 -0
  15. content_studio/router.py +14 -0
  16. content_studio/serializers.py +118 -0
  17. content_studio/settings.py +152 -0
  18. content_studio/static/content_studio/assets/browser-ponyfill-Ct7s-5jI.js +2 -0
  19. content_studio/static/content_studio/assets/browser-ponyfill-TyWUZ1Oq.js +2 -0
  20. content_studio/static/content_studio/assets/index.css +1 -0
  21. content_studio/static/content_studio/assets/index.js +249 -0
  22. content_studio/static/content_studio/assets/inter-cyrillic-ext-wght-normal.woff2 +0 -0
  23. content_studio/static/content_studio/assets/inter-cyrillic-wght-normal.woff2 +0 -0
  24. content_studio/static/content_studio/assets/inter-greek-ext-wght-normal.woff2 +0 -0
  25. content_studio/static/content_studio/assets/inter-greek-wght-normal.woff2 +0 -0
  26. content_studio/static/content_studio/assets/inter-latin-ext-wght-normal.woff2 +0 -0
  27. content_studio/static/content_studio/assets/inter-latin-wght-normal.woff2 +0 -0
  28. content_studio/static/content_studio/assets/inter-vietnamese-wght-normal.woff2 +0 -0
  29. content_studio/static/content_studio/icons/pi/Phosphor-Bold.svg +3057 -0
  30. content_studio/static/content_studio/icons/pi/Phosphor-Bold.ttf +0 -0
  31. content_studio/static/content_studio/icons/pi/Phosphor-Bold.woff +0 -0
  32. content_studio/static/content_studio/icons/pi/Phosphor-Bold.woff2 +0 -0
  33. content_studio/static/content_studio/icons/pi/style.css +4627 -0
  34. content_studio/static/content_studio/img/media_placeholder.svg +1 -0
  35. content_studio/static/content_studio/locales/en/translation.json +85 -0
  36. content_studio/static/content_studio/locales/nl/translation.json +90 -0
  37. content_studio/static/content_studio/vite.svg +1 -0
  38. content_studio/templates/content_studio/index.html +24 -0
  39. content_studio/token_backends/__init__.py +39 -0
  40. content_studio/token_backends/jwt.py +56 -0
  41. content_studio/urls.py +21 -0
  42. content_studio/utils.py +62 -0
  43. content_studio/views.py +181 -0
  44. content_studio/viewsets.py +114 -0
  45. content_studio/widgets.py +83 -0
  46. django_content_studio-1.0.0b5.dist-info/LICENSE +21 -0
  47. django_content_studio-1.0.0b5.dist-info/METADATA +86 -0
  48. django_content_studio-1.0.0b5.dist-info/RECORD +49 -0
  49. django_content_studio-1.0.0b5.dist-info/WHEEL +4 -0
@@ -0,0 +1,114 @@
1
+ import uuid
2
+
3
+ from django.contrib.admin.models import LogEntry, ADDITION, CHANGE, DELETION
4
+ from django.contrib.contenttypes.models import ContentType
5
+ from rest_framework.decorators import action
6
+ from rest_framework.exceptions import NotFound
7
+ from rest_framework.filters import SearchFilter, OrderingFilter
8
+ from rest_framework.parsers import JSONParser
9
+ from rest_framework.permissions import DjangoModelPermissions
10
+ from rest_framework.renderers import JSONRenderer
11
+ from rest_framework.viewsets import ModelViewSet
12
+
13
+ from .filters import LookupFilter
14
+ from .settings import cs_settings
15
+
16
+
17
+ class BaseModelViewSet(ModelViewSet):
18
+ lookup_field = "id"
19
+ is_singleton = False
20
+ parser_classes = [JSONParser]
21
+ renderer_classes = [JSONRenderer]
22
+ permission_classes = [DjangoModelPermissions]
23
+ filter_backends = [SearchFilter, OrderingFilter, LookupFilter]
24
+
25
+ def __init__(self, *args, **kwargs):
26
+ super(BaseModelViewSet, self).__init__()
27
+ admin_site = cs_settings.ADMIN_SITE
28
+
29
+ self.authentication_classes = [
30
+ admin_site.token_backend.active_backend.authentication_class
31
+ ]
32
+
33
+ def list(self, request, *args, **kwargs):
34
+ """
35
+ We overwrite the list method to support singletons. If a singleton
36
+ doesn't exist this will raise a NotFound exception.
37
+ """
38
+ if self.is_singleton:
39
+ return super().retrieve(request, *args, **kwargs)
40
+
41
+ return super().list(request, *args, **kwargs)
42
+
43
+ def perform_create(self, serializer):
44
+ instance = serializer.save()
45
+
46
+ if hasattr(instance, cs_settings.CREATED_BY_ATTR):
47
+ setattr(instance, cs_settings.CREATED_BY_ATTR, self.request.user)
48
+ instance.save()
49
+
50
+ content_type = ContentType.objects.get_for_model(instance)
51
+ LogEntry.objects.create(
52
+ user=self.request.user,
53
+ action_flag=ADDITION,
54
+ content_type=content_type,
55
+ object_id=instance.id,
56
+ object_repr=str(instance)[:200],
57
+ change_message="",
58
+ )
59
+
60
+ def perform_update(self, serializer):
61
+ instance = serializer.save()
62
+
63
+ if hasattr(instance, cs_settings.EDITED_BY_ATTR):
64
+ setattr(instance, cs_settings.EDITED_BY_ATTR, self.request.user)
65
+ instance.save()
66
+
67
+ content_type = ContentType.objects.get_for_model(instance)
68
+ LogEntry.objects.create(
69
+ user=self.request.user,
70
+ action_flag=CHANGE,
71
+ content_type=content_type,
72
+ object_id=instance.id,
73
+ object_repr=str(instance)[:200],
74
+ change_message="",
75
+ )
76
+
77
+ def perform_destroy(self, instance):
78
+ content_type = ContentType.objects.get_for_model(instance)
79
+ LogEntry.objects.create(
80
+ user=self.request.user,
81
+ action_flag=DELETION,
82
+ content_type=content_type,
83
+ object_id=instance.id,
84
+ object_repr=str(instance)[:200],
85
+ change_message="",
86
+ )
87
+
88
+ instance.delete()
89
+
90
+ def get_object(self):
91
+ """
92
+ We overwrite this method to add support for singletons.
93
+ If a singleton doesn't exist it will raise a NotFound exception.
94
+ """
95
+ if self.is_singleton:
96
+ singleton = self.get_queryset().first()
97
+
98
+ if singleton:
99
+ return singleton
100
+ else:
101
+ raise NotFound()
102
+
103
+ return super().get_object()
104
+
105
+ @action(
106
+ methods=["get"], detail=True, url_path="components/(?P<component_id>[^/.]+)"
107
+ )
108
+ def get_component(self, request, id, component_id):
109
+ component = self._admin_model.get_component(uuid.UUID(component_id))
110
+
111
+ if not component:
112
+ raise NotFound()
113
+
114
+ return component.handle_request(obj=self.get_object(), request=request)
@@ -0,0 +1,83 @@
1
+ ###
2
+ # Widgets determine what input field is used for a certain
3
+ # model field. Each Django model field has a default widget,
4
+ # but this can be overridden in the admin model.
5
+ ###
6
+
7
+
8
+ class BaseWidget:
9
+ @classmethod
10
+ def serialize(cls):
11
+ return {"name": cls.__name__}
12
+
13
+
14
+ class InputWidget(BaseWidget):
15
+ pass
16
+
17
+
18
+ class TextAreaWidget(BaseWidget):
19
+ pass
20
+
21
+
22
+ class SwitchWidget(BaseWidget):
23
+ pass
24
+
25
+
26
+ class CheckboxWidget(BaseWidget):
27
+ pass
28
+
29
+
30
+ class DateWidget(BaseWidget):
31
+ pass
32
+
33
+
34
+ class DateTimeWidget(BaseWidget):
35
+ pass
36
+
37
+
38
+ class TimeWidget(BaseWidget):
39
+ pass
40
+
41
+
42
+ class RichTextWidget(BaseWidget):
43
+ pass
44
+
45
+
46
+ class RadioButtonWidget(BaseWidget):
47
+ pass
48
+
49
+
50
+ class SelectWidget(BaseWidget):
51
+ pass
52
+
53
+
54
+ class MultiSelectWidget(BaseWidget):
55
+ pass
56
+
57
+
58
+ class URLPathWidget(BaseWidget):
59
+ pass
60
+
61
+
62
+ class SlugWidget(BaseWidget):
63
+ pass
64
+
65
+
66
+ class ForeignKeyWidget(BaseWidget):
67
+ pass
68
+
69
+
70
+ class ManyToManyWidget(BaseWidget):
71
+ pass
72
+
73
+
74
+ class JSONSchemaWidget(BaseWidget):
75
+ pass
76
+
77
+
78
+ class JSONWidget(BaseWidget):
79
+ pass
80
+
81
+
82
+ class MediaWidget(BaseWidget):
83
+ pass
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Leon van der Grient
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.
@@ -0,0 +1,86 @@
1
+ Metadata-Version: 2.3
2
+ Name: django-content-studio
3
+ Version: 1.0.0b5
4
+ Summary: Modern & flexible Django admin
5
+ License: MIT
6
+ Author: Leon van der Grient
7
+ Author-email: leon@devtastic.io
8
+ Requires-Python: >=3.10
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Description-Content-Type: text/markdown
16
+
17
+ # Django Content Studio
18
+
19
+ [![PyPI version](https://badge.fury.io/py/django-content-studio.svg)](https://badge.fury.io/py/django-content-studio)
20
+ [![Python versions](https://img.shields.io/pypi/pyversions/django-content-studio.svg)](https://pypi.org/project/django-content-studio/)
21
+ [![Django versions](https://img.shields.io/badge/django-5.0%2B-blue.svg)](https://www.djangoproject.com/)
22
+ [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
23
+
24
+ Django Content Studio is a modern, flexible alternative to the Django admin.
25
+
26
+ ## 🚀 Quick Start
27
+
28
+ ### Installation
29
+
30
+ ☝️ Django Content Studio depends on Django and Django Rest Framework.
31
+
32
+ ```bash
33
+ pip install django-content-studio
34
+ ```
35
+
36
+ ### Add to Django Settings
37
+
38
+ ```python
39
+ # settings.py
40
+ INSTALLED_APPS = [
41
+ 'django.contrib.admin',
42
+ 'django.contrib.auth',
43
+ 'django.contrib.contenttypes',
44
+ 'django.contrib.sessions',
45
+ 'django.contrib.messages',
46
+ 'django.contrib.staticfiles',
47
+ 'rest_framework',
48
+ 'content_studio', # Add this
49
+ # ... your apps
50
+ ]
51
+ ```
52
+ ### Add URLs
53
+
54
+ ```python
55
+ # urls.py
56
+ urlpatterns = [
57
+ path("admin/", include("content_studio.urls")),
58
+ # ... your urls
59
+ ]
60
+ ```
61
+
62
+ ## 🐛 Issues & Support
63
+
64
+ - 🐛 **Bug Reports**: [GitHub Issues](https://github.com/BitsOfAbstraction/django-content-studio/issues)
65
+ - 💬 **Discussions**: [GitHub Discussions](https://github.com/BitsOfAbstraction/django-content-studio/discussions)
66
+ - 📧 **Email**: leon@devtastic.io
67
+
68
+ ## 📄 License
69
+
70
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
71
+
72
+ ## 🙏 Acknowledgments
73
+
74
+ - Built with React and Tailwind CSS
75
+ - Inspired by the original Django admin
76
+ - Thanks to all contributors and the Django community
77
+
78
+ ## 🔗 Links
79
+
80
+ - [PyPI Package](https://pypi.org/project/django-content-studio/)
81
+ - [GitHub Repository](https://github.com/BitsOfAbstraction/django-content-studio)
82
+ - [Changelog](CHANGELOG.md)
83
+
84
+ ---
85
+
86
+ Made in Europe 🇪🇺 with 💚 for Django
@@ -0,0 +1,49 @@
1
+ content_studio/__init__.py,sha256=CDiN76rZPcVxt5ylj9YwLB8I9P07Ez2onA2znW-CPyI,161
2
+ content_studio/admin.py,sha256=BpPdw4g0uQMPPgNObxQzVGbTNzZWDc1L0L3gI_WA8WI,10260
3
+ content_studio/apps.py,sha256=cfZvEixECgLN0g2zbu_Y94u5k3QBMyr_bgsgj4qYuoA,3503
4
+ content_studio/dashboard/__init__.py,sha256=1GQcAuM5IlTlvqq6aPYA_QfuiEy_It0qx54VqDMQHCQ,1788
5
+ content_studio/dashboard/activity_log.py,sha256=Yr5F7wRFBnT7RlvWJb9gdwYZzEuEeQV4dhc6YXDCOPY,859
6
+ content_studio/filters.py,sha256=GyglR2E_wswomW7EnfShEXr14zxuRlLAuxrHVO3QQYg,4335
7
+ content_studio/form.py,sha256=tpPl3mIj6fIqfLisKxlgSjkY75bVaOmM2T9R7Gwca28,4793
8
+ content_studio/formats.py,sha256=JzOWrDRCVSnjJI0oX5fyFQU8LC634_jeAe84Widy43U,786
9
+ content_studio/login_backends/__init__.py,sha256=hgPJh9hFobubImfhynaeZ_dku3sjqNQvN5B43TVg7Gw,643
10
+ content_studio/login_backends/username_password.py,sha256=JJbF3oWnhOwLs-WaqclCCH6nAnrhlKbyBUzAJKVtq7A,2561
11
+ content_studio/media_library/serializers.py,sha256=1MPFqbZdE0iTYqZrzzYoT_y4q0ItGTbQ-I7omyojAZo,660
12
+ content_studio/media_library/viewsets.py,sha256=XsQuCrcfZ52xvvsEbHZ2WTI99wf-cheOKfaMJyfAJbo,4318
13
+ content_studio/models.py,sha256=SLcgMIXu4FqwbQJBQ-jLw7_hlGjbSmwHmyKfzDsj-2M,2068
14
+ content_studio/paginators.py,sha256=XrA6ECP2pO75SSj0Mi0Jqj7n_YPuIin-V8_6EOaQj64,589
15
+ content_studio/router.py,sha256=7Up_sipGaUDoY6ElJNRf85ADaYfJCWV4To523L4LGuw,393
16
+ content_studio/serializers.py,sha256=k5QLRiaa85jEiyljz2QdyTFcWY4gT8Lb28dBZsdEcsQ,3674
17
+ content_studio/settings.py,sha256=6U0o-DxwpFQo-1LLumr3U4FCVTHiBzySK7M77HWvpf4,4510
18
+ content_studio/static/content_studio/assets/browser-ponyfill-Ct7s-5jI.js,sha256=ka_XS-3zL9SFKN25BR2iVt7ZrWLHsY-13dDUJinsL10,10281
19
+ content_studio/static/content_studio/assets/browser-ponyfill-TyWUZ1Oq.js,sha256=sKLpD8vGwLfnJVLaSGMMi8krArcm2Qj3-igVwDvLMek,10287
20
+ content_studio/static/content_studio/assets/index.css,sha256=1JQ24WmyIaTM9wU2Bt51aVZwvBo2fYiEo4NXU7l_zm8,84701
21
+ content_studio/static/content_studio/assets/index.js,sha256=X5GGDNBJleyi3BzJeGKZF65u3Qw6iAmtjiMNFDziXBg,1409624
22
+ content_studio/static/content_studio/assets/inter-cyrillic-ext-wght-normal.woff2,sha256=yhVwYzOaxK1BjyFPOr_tEZsHmKtNN3OGzlyeWnpDXr0,25960
23
+ content_studio/static/content_studio/assets/inter-cyrillic-wght-normal.woff2,sha256=cdXuk8wenx1SCjqLZkVt4Yx4edjfCdV_zS6v91_vAHU,18748
24
+ content_studio/static/content_studio/assets/inter-greek-ext-wght-normal.woff2,sha256=bp4CCiX5tW1BjywIWx08CXJaTaI_5pOltGMGRgZzIZA,11232
25
+ content_studio/static/content_studio/assets/inter-greek-wght-normal.woff2,sha256=G-NEjikvvwX_4Xb-HkPxNQE9ULHn0yStGlWPYj07tvY,18996
26
+ content_studio/static/content_studio/assets/inter-latin-ext-wght-normal.woff2,sha256=NLnFBMq3pz43t0Y0OkSRMuVs97VIGvLLgdx03P8lyVY,85068
27
+ content_studio/static/content_studio/assets/inter-latin-wght-normal.woff2,sha256=MQDndehhbNJhG-7PojpCY9cDdYZ4m0PwNSNqLm-9TGI,48256
28
+ content_studio/static/content_studio/assets/inter-vietnamese-wght-normal.woff2,sha256=XGb54H6QxtSsSSLMaNYN4mwXsYWOZ3-15gP845UrP_I,10252
29
+ content_studio/static/content_studio/icons/pi/Phosphor-Bold.svg,sha256=4kdzmyaGcNVhK6qRIA8PdhaZ7raHU0xoU26ht52VG_c,2967217
30
+ content_studio/static/content_studio/icons/pi/Phosphor-Bold.ttf,sha256=EKChy0-BVqQg-fhM80xOmHHljtLd6h9qgHmtByQ6f7I,495308
31
+ content_studio/static/content_studio/icons/pi/Phosphor-Bold.woff,sha256=3k3MnRjPMzY8GdLJJMnZ1R4hCXi9Pm7FCK7HFnCz2wY,495388
32
+ content_studio/static/content_studio/icons/pi/Phosphor-Bold.woff2,sha256=IVO1LOqeBvwMyElgSL5IWzgaD4vxMK3qWpdW_I8QC4c,150052
33
+ content_studio/static/content_studio/icons/pi/style.css,sha256=yKMt9n-L1X9wxjceFewjLfJd3ro-uQYNeqpoEBps4kA,85821
34
+ content_studio/static/content_studio/img/media_placeholder.svg,sha256=ZLrfeqvaC5YwuHAg_7YJXLhYzLz2azVcKqCLEGOVTTs,3253
35
+ content_studio/static/content_studio/locales/en/translation.json,sha256=57r6oc0gX-YTkDraToBWZDCTxLIRzjV7TgL0qE8i0pI,2342
36
+ content_studio/static/content_studio/locales/nl/translation.json,sha256=8hD3dpyE7fPio5dfafqW7fMU2gm65RIHq4RFE19jYgU,2573
37
+ content_studio/static/content_studio/vite.svg,sha256=SnSK_UQ5GLsWWRyDTEAdrjPoeGGrXbrQgRw6O0qSFPs,1497
38
+ content_studio/templates/content_studio/index.html,sha256=zGS8iro3w1HLs5hLbDRTrchB50rAaFqXbTMu7hdVz6E,1193
39
+ content_studio/token_backends/__init__.py,sha256=dO3aWIHXX8He399ZEvlS4fNgyL84OY9TEtkva9b5N5Q,1183
40
+ content_studio/token_backends/jwt.py,sha256=niGCpRqaUVhhS9haXfH1uFlg2v8NLB5IpsJ4N79Q0Gg,1565
41
+ content_studio/urls.py,sha256=EY7lbzC0Q5vLfvqE3rK_4hmDrXhTuxKzYC55cc5tEEo,701
42
+ content_studio/utils.py,sha256=xOolXd9Zmty6B6_2febvM8TmZhZ0JRc2nCLj3VooHkM,1488
43
+ content_studio/views.py,sha256=GbANmQY_VyzQPD4Hw3MEfWF3pOr2G6a61Ktvu2Bw6d8,5370
44
+ content_studio/viewsets.py,sha256=MdKpW5LsEbCuc1fDvGYQLgOf208aYTbJBYAKKhFzJiU,3813
45
+ content_studio/widgets.py,sha256=OlFKCAYNhkj2Ww9S_hvQTzUjcSnYXocmi04zusKrOTo,1071
46
+ django_content_studio-1.0.0b5.dist-info/LICENSE,sha256=Wnx2EJhtSNnXE5Qs80i1HTBNFZTi8acEtC5TYqtFlnQ,1075
47
+ django_content_studio-1.0.0b5.dist-info/METADATA,sha256=gj3eo-1DU5nQZcaDIK1NxZmT8YtLnsty_NaPs76o_9w,2512
48
+ django_content_studio-1.0.0b5.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
49
+ django_content_studio-1.0.0b5.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.1.3
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any