utg-base 1.0.0__tar.gz → 1.1.0__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: utg-base
3
- Version: 1.0.0
3
+ Version: 1.1.0
4
4
  Summary: UTG Base Package
5
5
  Author: Rovshen
6
6
  Author-email: rovshenashirov1619@gmail.com
@@ -10,8 +10,8 @@ Requires-Dist: croniter (>=2.0.3,<3.0.0)
10
10
  Requires-Dist: django (>=5.2.7,<6.0.0)
11
11
  Requires-Dist: django-filter (>=23.5,<24.0)
12
12
  Requires-Dist: djangorestframework (>=3.16.1,<4.0.0)
13
- Requires-Dist: djangorestframework-simplejwt[crypto] (>=5.3.1,<6.0.0)
14
- Requires-Dist: drf-spectacular[sidecar] (>=0.27.1,<0.28.0)
13
+ Requires-Dist: djangorestframework-simplejwt[crypto] (>=5.5.1,<6.0.0)
14
+ Requires-Dist: drf-spectacular[sidecar] (>=0.29.0,<0.30.0)
15
15
  Requires-Dist: inflect (>=7.2.1,<8.0.0)
16
16
  Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
17
17
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "utg-base"
3
- version = "1.0.0"
3
+ version = "1.1.0"
4
4
  description = "UTG Base Package"
5
5
  authors = ["Rovshen <rovshenashirov1619@gmail.com>"]
6
6
  readme = "README.md"
@@ -8,11 +8,11 @@ readme = "README.md"
8
8
  [tool.poetry.dependencies]
9
9
  python = "^3.14"
10
10
  djangorestframework = "^3.16.1"
11
- djangorestframework-simplejwt = { extras = ["crypto"], version = "^5.3.1" }
11
+ djangorestframework-simplejwt = {extras = ["crypto"], version = "^5.5.1"}
12
12
  django = "^5.2.7"
13
13
  django-filter = "^23.5"
14
14
  croniter = "^2.0.3"
15
- drf-spectacular = {extras = ["sidecar"], version = "^0.27.1"}
15
+ drf-spectacular = {extras = ["sidecar"], version = "^0.29.0"}
16
16
  openpyxl = "^3.1.2"
17
17
  inflect = "^7.2.1"
18
18
 
@@ -0,0 +1,2 @@
1
+ from energy_base.models.jwt_user import JWTUser
2
+ from energy_base.models.deviation_reason_type import DeviationReasonType
@@ -0,0 +1,11 @@
1
+ from rest_framework_simplejwt.models import TokenUser
2
+ from rest_framework_simplejwt.tokens import Token
3
+
4
+
5
+ class JWTUser(TokenUser):
6
+
7
+ def __init__(self, token: "Token"):
8
+ super().__init__(token)
9
+ self.phone = self.token.get("phone")
10
+ self._groups = self.token.get("groups")
11
+ self.should_cache_requests = self.token.get("should_cache_requests")
File without changes
@@ -0,0 +1,3 @@
1
+ from django.contrib import admin
2
+
3
+ # Register your models here.
@@ -0,0 +1,6 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class ReferencesApiConfig(AppConfig):
5
+ default_auto_field = 'django.db.models.BigAutoField'
6
+ name = 'utg_base.references_api'
@@ -0,0 +1,3 @@
1
+ from django.db import models
2
+
3
+ # Create your models here.
@@ -0,0 +1,13 @@
1
+ from .utils import get_model_classes, create_view_set, get_basename, get_url_prefix
2
+ from ..api.routers import OptionalSlashRouter
3
+
4
+ router = OptionalSlashRouter()
5
+
6
+ for model_class in get_model_classes():
7
+ router.register(
8
+ prefix=get_url_prefix(model_class),
9
+ viewset=create_view_set(model_class),
10
+ basename=get_basename(model_class)
11
+ )
12
+
13
+ urlpatterns = router.urls
@@ -0,0 +1,181 @@
1
+ import importlib
2
+ from urllib.parse import urlparse
3
+
4
+ import inflect
5
+ from django.conf import settings
6
+ from django.db.models import Model, CharField
7
+ from drf_spectacular.utils import extend_schema, extend_schema_serializer
8
+ from rest_framework import filters
9
+ from rest_framework import viewsets, serializers
10
+
11
+ from ..api.views import TranslatedListView
12
+
13
+ serializer_classes = {}
14
+
15
+
16
+ def find_model(model_name: str):
17
+ for model_class in get_model_classes():
18
+ if get_model_class_name(model_class).lower() == model_name.lower():
19
+ return model_class
20
+
21
+
22
+ def get_api_meta_property(model: Model, property_name: str):
23
+ if hasattr(model, 'ApiMeta'):
24
+ if hasattr(model.ApiMeta, property_name):
25
+ return getattr(model.ApiMeta, property_name)
26
+
27
+
28
+ def get_model_class_name(model: Model):
29
+ return model._meta.object_name
30
+
31
+
32
+ def get_model_fields_list(model: Model):
33
+ return model._meta.get_fields()
34
+
35
+
36
+ def get_view_set_name(model: Model):
37
+ return get_model_class_name(model) + 'ViewSet'
38
+
39
+
40
+ def get_basename(model: Model):
41
+ return 'admin-' + get_plural_form(get_model_class_name(model).lower())
42
+
43
+
44
+ def camel_to_snake(name: str):
45
+ return ''.join(map(lambda c: '-' + c.lower() if c.isupper() else c, name)).removeprefix('-')
46
+
47
+
48
+ def get_url_prefix(model: Model):
49
+ return 'admin/' + get_plural_form(camel_to_snake(get_model_class_name(model))).replace(' ', '-')
50
+
51
+
52
+ def get_plural_form(word: str):
53
+ p = inflect.engine()
54
+ return p.plural(word)
55
+
56
+
57
+ def get_serializer_name(model: Model):
58
+ return get_model_class_name(model) + 'Serializer'
59
+
60
+
61
+ def get_ordering(model: Model):
62
+ if model._meta.ordering:
63
+ return model._meta.ordering
64
+ if hasattr(model, 'created_at'):
65
+ return ('-created_at',)
66
+ if hasattr(model, 'id'):
67
+ return ('id',)
68
+ return ()
69
+
70
+
71
+ def get_model_classes():
72
+ model_classes = []
73
+ for model_import_path in settings.REFERENCE_API_MODELS:
74
+ module_name, class_name = model_import_path.rsplit('.', 1)
75
+ module = importlib.import_module(module_name)
76
+ model_classes.append(getattr(module, class_name))
77
+
78
+ return model_classes
79
+
80
+
81
+ def create_view_set(model: Model):
82
+ fields_list = get_model_fields_list(model)
83
+
84
+ @extend_schema(tags=[get_url_prefix(model)])
85
+ class ViewSet(viewsets.ModelViewSet, TranslatedListView):
86
+ http_method_names = get_api_meta_property(model, 'http_method_names') or ['get', 'patch']
87
+ manager = model.objects.order_by(*get_ordering(model))
88
+ filter_backends = [filters.SearchFilter]
89
+ search_fields = (get_api_meta_property(model, 'search_fields') or
90
+ [field.name for field in fields_list if isinstance(field, CharField)])
91
+
92
+ def get_serializer_class(self):
93
+ if self.action == 'create':
94
+ return create_serializer_for_create(model)
95
+
96
+ if self.action == 'partial_update':
97
+ return create_serializer_for_partial_update(model)
98
+
99
+ return create_serializer(model)
100
+
101
+ return ViewSet
102
+
103
+
104
+ def create_serializer_for_create(model: Model):
105
+ @extend_schema_serializer(component_name='Admin' + get_serializer_name(model))
106
+ class Serializer(serializers.ModelSerializer):
107
+ class Meta:
108
+ fields = '__all__'
109
+
110
+ Serializer.Meta.model = model
111
+ return Serializer
112
+
113
+
114
+ def create_serializer_for_partial_update(model: Model):
115
+ fields_list = get_model_fields_list(model)
116
+
117
+ @extend_schema_serializer(component_name='Admin' + get_serializer_name(model))
118
+ class Serializer(serializers.ModelSerializer):
119
+ class Meta:
120
+ fields = '__all__'
121
+ read_only_fields = list(
122
+ {
123
+ 'created_at',
124
+ 'updated_at',
125
+ 'deleted_at',
126
+ 'created_by',
127
+ 'updated_by',
128
+ 'deleted_by',
129
+ 'code'
130
+ } & set([field.name for field in fields_list])
131
+ )
132
+
133
+ Serializer.Meta.model = model
134
+ return Serializer
135
+
136
+
137
+ def create_serializer(model: Model, depth=0):
138
+ if get_model_class_name(model) in serializer_classes:
139
+ return serializer_classes[get_model_class_name(model)]
140
+
141
+ fields_list = get_model_fields_list(model)
142
+
143
+ class ImageNameField(serializers.ImageField):
144
+ def to_representation(self, value):
145
+ if not value:
146
+ return None
147
+ parsed_url = urlparse(value.url)
148
+ return f'{parsed_url.path}?{parsed_url.query}'
149
+
150
+ @extend_schema_serializer(component_name='Admin' + get_serializer_name(model))
151
+ class Serializer(serializers.ModelSerializer):
152
+ def __init__(self, *args, **kwargs):
153
+ super().__init__(*args, **kwargs)
154
+ nonlocal model, fields_list
155
+ for field in fields_list:
156
+ if field.__class__.__name__.endswith('ImageField') or field.__class__.__name__.endswith('FileField'):
157
+ self.fields[field.name] = ImageNameField()
158
+
159
+ if field.__class__.__name__.endswith('ForeignKey'):
160
+ model_name = field.name
161
+ _model = find_model(model_name)
162
+ if _model is not None and depth == 0:
163
+ self.fields[model_name] = create_serializer(_model, depth + 1)()
164
+
165
+ class Meta:
166
+ fields = '__all__'
167
+ read_only_fields = list(
168
+ {
169
+ 'created_at',
170
+ 'updated_at',
171
+ 'deleted_at',
172
+ 'created_by',
173
+ 'updated_by',
174
+ 'deleted_by',
175
+ 'code'
176
+ } & set([field.name for field in fields_list])
177
+ )
178
+
179
+ Serializer.Meta.model = model
180
+ serializer_classes[get_model_class_name(model)] = Serializer
181
+ return Serializer
File without changes