GeneralManager 0.7.0__py3-none-any.whl → 0.9.0__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.
- general_manager/api/graphql.py +117 -65
- general_manager/api/mutation.py +11 -10
- general_manager/apps.py +62 -34
- general_manager/auxiliary/formatString.py +60 -0
- general_manager/interface/baseInterface.py +1 -0
- general_manager/interface/databaseBasedInterface.py +25 -78
- general_manager/interface/databaseInterface.py +49 -14
- general_manager/interface/models.py +88 -0
- general_manager/interface/readOnlyInterface.py +35 -28
- general_manager/manager/generalManager.py +73 -14
- general_manager/manager/input.py +9 -12
- general_manager/manager/meta.py +26 -12
- general_manager/utils/testing.py +124 -0
- {generalmanager-0.7.0.dist-info → generalmanager-0.9.0.dist-info}/METADATA +1 -1
- {generalmanager-0.7.0.dist-info → generalmanager-0.9.0.dist-info}/RECORD +18 -15
- {generalmanager-0.7.0.dist-info → generalmanager-0.9.0.dist-info}/WHEEL +0 -0
- {generalmanager-0.7.0.dist-info → generalmanager-0.9.0.dist-info}/licenses/LICENSE +0 -0
- {generalmanager-0.7.0.dist-info → generalmanager-0.9.0.dist-info}/top_level.txt +0 -0
@@ -1,12 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from typing import
|
3
|
-
Type,
|
4
|
-
ClassVar,
|
5
|
-
Any,
|
6
|
-
Callable,
|
7
|
-
TYPE_CHECKING,
|
8
|
-
TypeVar,
|
9
|
-
)
|
2
|
+
from typing import Type, ClassVar, Any, Callable, TYPE_CHECKING, TypeVar, Generic
|
10
3
|
from django.db import models
|
11
4
|
from django.conf import settings
|
12
5
|
from datetime import datetime, timedelta
|
@@ -30,6 +23,11 @@ from general_manager.interface.baseInterface import (
|
|
30
23
|
)
|
31
24
|
from general_manager.manager.input import Input
|
32
25
|
from general_manager.bucket.databaseBucket import DatabaseBucket
|
26
|
+
from general_manager.interface.models import (
|
27
|
+
GeneralManagerBasisModel,
|
28
|
+
GeneralManagerModel,
|
29
|
+
getFullCleanMethode,
|
30
|
+
)
|
33
31
|
|
34
32
|
if TYPE_CHECKING:
|
35
33
|
from general_manager.manager.generalManager import GeneralManager
|
@@ -39,69 +37,11 @@ if TYPE_CHECKING:
|
|
39
37
|
modelsModel = TypeVar("modelsModel", bound=models.Model)
|
40
38
|
|
41
39
|
|
42
|
-
|
43
|
-
"""
|
44
|
-
Generates a custom `full_clean` method for a Django model that combines standard validation with additional rule-based checks.
|
45
|
-
|
46
|
-
The returned method first performs Django's built-in model validation, then evaluates any custom rules defined in the model's `_meta.rules` attribute. If any validation or rule fails, a `ValidationError` is raised containing all collected errors.
|
47
|
-
"""
|
48
|
-
|
49
|
-
def full_clean(self: models.Model, *args: Any, **kwargs: Any):
|
50
|
-
errors: dict[str, Any] = {}
|
51
|
-
try:
|
52
|
-
super(model, self).full_clean(*args, **kwargs) # type: ignore
|
53
|
-
except ValidationError as e:
|
54
|
-
errors.update(e.message_dict)
|
55
|
-
|
56
|
-
rules: list[Rule] = getattr(self._meta, "rules")
|
57
|
-
for rule in rules:
|
58
|
-
if not rule.evaluate(self):
|
59
|
-
error_message = rule.getErrorMessage()
|
60
|
-
if error_message:
|
61
|
-
errors.update(error_message)
|
62
|
-
|
63
|
-
if errors:
|
64
|
-
raise ValidationError(errors)
|
65
|
-
|
66
|
-
return full_clean
|
40
|
+
MODEL_TYPE = TypeVar("MODEL_TYPE", bound=GeneralManagerBasisModel)
|
67
41
|
|
68
42
|
|
69
|
-
class
|
70
|
-
|
71
|
-
is_active = models.BooleanField(default=True)
|
72
|
-
history = HistoricalRecords(inherit=True)
|
73
|
-
|
74
|
-
class Meta:
|
75
|
-
abstract = True
|
76
|
-
|
77
|
-
|
78
|
-
class GeneralManagerModel(GeneralManagerBasisModel):
|
79
|
-
changed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
|
80
|
-
changed_by_id: int
|
81
|
-
|
82
|
-
@property
|
83
|
-
def _history_user(self) -> AbstractUser:
|
84
|
-
"""
|
85
|
-
Returns the user who last modified this model instance.
|
86
|
-
"""
|
87
|
-
return self.changed_by
|
88
|
-
|
89
|
-
@_history_user.setter
|
90
|
-
def _history_user(self, value: AbstractUser) -> None:
|
91
|
-
"""
|
92
|
-
Sets the user responsible for the latest change to the model instance.
|
93
|
-
|
94
|
-
Args:
|
95
|
-
value: The user to associate with the change.
|
96
|
-
"""
|
97
|
-
self.changed_by = value
|
98
|
-
|
99
|
-
class Meta: # type: ignore
|
100
|
-
abstract = True
|
101
|
-
|
102
|
-
|
103
|
-
class DBBasedInterface(InterfaceBase):
|
104
|
-
_model: Type[GeneralManagerBasisModel]
|
43
|
+
class DBBasedInterface(InterfaceBase, Generic[MODEL_TYPE]):
|
44
|
+
_model: Type[MODEL_TYPE]
|
105
45
|
input_fields: dict[str, Input] = {"id": Input(int)}
|
106
46
|
|
107
47
|
def __init__(
|
@@ -111,9 +51,9 @@ class DBBasedInterface(InterfaceBase):
|
|
111
51
|
**kwargs: dict[str, Any],
|
112
52
|
):
|
113
53
|
"""
|
114
|
-
|
115
|
-
|
116
|
-
If
|
54
|
+
Initialize the interface and load the associated model instance.
|
55
|
+
|
56
|
+
If `search_date` is provided, loads the historical record as of that date; otherwise, loads the current record.
|
117
57
|
"""
|
118
58
|
super().__init__(*args, **kwargs)
|
119
59
|
self.pk = self.identification["id"]
|
@@ -200,9 +140,12 @@ class DBBasedInterface(InterfaceBase):
|
|
200
140
|
@classmethod
|
201
141
|
def getAttributeTypes(cls) -> dict[str, AttributeTypedDict]:
|
202
142
|
"""
|
203
|
-
|
204
|
-
|
205
|
-
The
|
143
|
+
Return a dictionary mapping attribute names to metadata describing their types and properties.
|
144
|
+
|
145
|
+
The dictionary includes all model fields, custom fields, foreign keys, many-to-many, and reverse relation fields. For each attribute, the metadata specifies its Python type (translated from Django field types when possible), whether it is required, editable, derived, and its default value. For related models with a general manager class, the type is set to that class.
|
146
|
+
|
147
|
+
Returns:
|
148
|
+
dict[str, AttributeTypedDict]: Mapping of attribute names to their type information and metadata.
|
206
149
|
"""
|
207
150
|
TRANSLATION: dict[Type[models.Field[Any, Any]], type] = {
|
208
151
|
models.fields.BigAutoField: int,
|
@@ -228,6 +171,7 @@ class DBBasedInterface(InterfaceBase):
|
|
228
171
|
field: models.Field = getattr(cls._model, field_name)
|
229
172
|
fields[field_name] = {
|
230
173
|
"type": type(field),
|
174
|
+
"is_derived": False,
|
231
175
|
"is_required": not field.null,
|
232
176
|
"is_editable": field.editable,
|
233
177
|
"default": field.default,
|
@@ -238,6 +182,7 @@ class DBBasedInterface(InterfaceBase):
|
|
238
182
|
field: models.Field = getattr(cls._model, field_name).field
|
239
183
|
fields[field_name] = {
|
240
184
|
"type": type(field),
|
185
|
+
"is_derived": False,
|
241
186
|
"is_required": not field.null,
|
242
187
|
"is_editable": field.editable,
|
243
188
|
"default": field.default,
|
@@ -255,6 +200,7 @@ class DBBasedInterface(InterfaceBase):
|
|
255
200
|
elif related_model is not None:
|
256
201
|
fields[field_name] = {
|
257
202
|
"type": related_model,
|
203
|
+
"is_derived": False,
|
258
204
|
"is_required": not field.null,
|
259
205
|
"is_editable": field.editable,
|
260
206
|
"default": field.default,
|
@@ -280,6 +226,7 @@ class DBBasedInterface(InterfaceBase):
|
|
280
226
|
fields[f"{field_name}_list"] = {
|
281
227
|
"type": related_model,
|
282
228
|
"is_required": False,
|
229
|
+
"is_derived": not bool(field.many_to_many),
|
283
230
|
"is_editable": bool(field.many_to_many and field.editable),
|
284
231
|
"default": None,
|
285
232
|
}
|
@@ -453,9 +400,9 @@ class DBBasedInterface(InterfaceBase):
|
|
453
400
|
) -> tuple[attributes, interfaceBaseClass, relatedClass]:
|
454
401
|
# Felder aus der Interface-Klasse sammeln
|
455
402
|
"""
|
456
|
-
Dynamically
|
403
|
+
Dynamically generates a Django model class, its associated interface class, and a factory class from an interface definition.
|
457
404
|
|
458
|
-
This method
|
405
|
+
This method collects fields and metadata from the provided interface class, creates a new Django model inheriting from the specified base model class, attaches custom validation rules if present, and constructs corresponding interface and factory classes. The updated attributes dictionary, the new interface class, and the newly created model class are returned for integration into the general manager framework.
|
459
406
|
|
460
407
|
Parameters:
|
461
408
|
name: The name for the dynamically created model class.
|
@@ -464,7 +411,7 @@ class DBBasedInterface(InterfaceBase):
|
|
464
411
|
base_model_class: The base class to use for the new model (defaults to GeneralManagerModel).
|
465
412
|
|
466
413
|
Returns:
|
467
|
-
A tuple containing the updated attributes dictionary, the new interface class, and the newly created model class.
|
414
|
+
tuple: A tuple containing the updated attributes dictionary, the new interface class, and the newly created model class.
|
468
415
|
"""
|
469
416
|
model_fields: dict[str, Any] = {}
|
470
417
|
meta_class = None
|
@@ -11,14 +11,25 @@ from general_manager.interface.databaseBasedInterface import (
|
|
11
11
|
)
|
12
12
|
|
13
13
|
|
14
|
-
class DatabaseInterface(DBBasedInterface):
|
14
|
+
class DatabaseInterface(DBBasedInterface[GeneralManagerModel]):
|
15
15
|
_interface_type = "database"
|
16
16
|
|
17
17
|
@classmethod
|
18
18
|
def create(
|
19
|
-
cls, creator_id: int, history_comment: str | None = None, **kwargs: Any
|
19
|
+
cls, creator_id: int | None, history_comment: str | None = None, **kwargs: Any
|
20
20
|
) -> int:
|
21
|
+
"""
|
22
|
+
Create a new model instance with the provided attributes and optional history tracking.
|
23
|
+
|
24
|
+
Validates input attributes, separates and sets many-to-many relationships, saves the instance with optional creator and history comment, and returns the primary key of the created instance.
|
25
|
+
|
26
|
+
Parameters:
|
27
|
+
creator_id (int | None): The ID of the user creating the instance, or None if not applicable.
|
28
|
+
history_comment (str | None): Optional comment to record in the instance's history.
|
21
29
|
|
30
|
+
Returns:
|
31
|
+
int: The primary key of the newly created instance.
|
32
|
+
"""
|
22
33
|
cls._checkForInvalidKwargs(cls._model, kwargs=kwargs)
|
23
34
|
kwargs, many_to_many_kwargs = cls._sortKwargs(cls._model, kwargs)
|
24
35
|
instance = cls.__setAttrForWrite(cls._model(), kwargs)
|
@@ -27,9 +38,18 @@ class DatabaseInterface(DBBasedInterface):
|
|
27
38
|
return pk
|
28
39
|
|
29
40
|
def update(
|
30
|
-
self, creator_id: int, history_comment: str | None = None, **kwargs: Any
|
41
|
+
self, creator_id: int | None, history_comment: str | None = None, **kwargs: Any
|
31
42
|
) -> int:
|
43
|
+
"""
|
44
|
+
Update the current model instance with new attribute values and many-to-many relationships, saving changes with optional history tracking.
|
45
|
+
|
46
|
+
Parameters:
|
47
|
+
creator_id (int | None): The ID of the user making the update, or None if not specified.
|
48
|
+
history_comment (str | None): An optional comment describing the reason for the update.
|
32
49
|
|
50
|
+
Returns:
|
51
|
+
int: The primary key of the updated instance.
|
52
|
+
"""
|
33
53
|
self._checkForInvalidKwargs(self._model, kwargs=kwargs)
|
34
54
|
kwargs, many_to_many_kwargs = self._sortKwargs(self._model, kwargs)
|
35
55
|
instance = self.__setAttrForWrite(self._model.objects.get(pk=self.pk), kwargs)
|
@@ -37,7 +57,19 @@ class DatabaseInterface(DBBasedInterface):
|
|
37
57
|
self.__setManyToManyAttributes(instance, many_to_many_kwargs)
|
38
58
|
return pk
|
39
59
|
|
40
|
-
def deactivate(
|
60
|
+
def deactivate(
|
61
|
+
self, creator_id: int | None, history_comment: str | None = None
|
62
|
+
) -> int:
|
63
|
+
"""
|
64
|
+
Deactivate the current model instance by setting its `is_active` flag to `False` and recording the change with an optional history comment.
|
65
|
+
|
66
|
+
Parameters:
|
67
|
+
creator_id (int | None): The ID of the user performing the deactivation, or None if not specified.
|
68
|
+
history_comment (str | None): An optional comment to include in the instance's history log.
|
69
|
+
|
70
|
+
Returns:
|
71
|
+
int: The primary key of the deactivated instance.
|
72
|
+
"""
|
41
73
|
instance = self._model.objects.get(pk=self.pk)
|
42
74
|
instance.is_active = False
|
43
75
|
if history_comment:
|
@@ -79,7 +111,12 @@ class DatabaseInterface(DBBasedInterface):
|
|
79
111
|
if isinstance(value, GeneralManager):
|
80
112
|
value = value.identification["id"]
|
81
113
|
key = f"{key}_id"
|
82
|
-
|
114
|
+
try:
|
115
|
+
setattr(instance, key, value)
|
116
|
+
except ValueError as e:
|
117
|
+
raise ValueError(f"Invalid value for {key}: {value}") from e
|
118
|
+
except TypeError as e:
|
119
|
+
raise TypeError(f"Type error for {key}: {e}") from e
|
83
120
|
return instance
|
84
121
|
|
85
122
|
@staticmethod
|
@@ -89,7 +126,7 @@ class DatabaseInterface(DBBasedInterface):
|
|
89
126
|
for key in kwargs:
|
90
127
|
temp_key = key.split("_id_list")[0] # Remove '_id_list' suffix
|
91
128
|
if temp_key not in attributes and temp_key not in field_names:
|
92
|
-
raise ValueError(f"{key} does not
|
129
|
+
raise ValueError(f"{key} does not exist in {model.__name__}")
|
93
130
|
|
94
131
|
@staticmethod
|
95
132
|
def _sortKwargs(
|
@@ -106,17 +143,15 @@ class DatabaseInterface(DBBasedInterface):
|
|
106
143
|
@classmethod
|
107
144
|
@transaction.atomic
|
108
145
|
def _save_with_history(
|
109
|
-
cls,
|
146
|
+
cls,
|
147
|
+
instance: GeneralManagerModel,
|
148
|
+
creator_id: int | None,
|
149
|
+
history_comment: str | None,
|
110
150
|
) -> int:
|
111
151
|
"""
|
112
|
-
|
152
|
+
Atomically saves a model instance with validation and optional history comment.
|
113
153
|
|
114
|
-
Sets the `changed_by_id` field, validates the instance, applies a history comment if provided, and saves the instance within
|
115
|
-
|
116
|
-
Args:
|
117
|
-
instance: The model instance to save.
|
118
|
-
creator_id: The ID of the user making the change.
|
119
|
-
history_comment: Optional comment describing the reason for the change.
|
154
|
+
Sets the `changed_by_id` field, validates the instance, applies a history comment if provided, and saves the instance within a database transaction.
|
120
155
|
|
121
156
|
Returns:
|
122
157
|
The primary key of the saved instance.
|
@@ -0,0 +1,88 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import Type, ClassVar, Any, Callable, TYPE_CHECKING, TypeVar
|
3
|
+
from django.db import models
|
4
|
+
from django.conf import settings
|
5
|
+
from simple_history.models import HistoricalRecords # type: ignore
|
6
|
+
from django.core.exceptions import ValidationError
|
7
|
+
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from general_manager.manager.generalManager import GeneralManager
|
11
|
+
from django.contrib.auth.models import AbstractUser
|
12
|
+
from general_manager.rule.rule import Rule
|
13
|
+
|
14
|
+
modelsModel = TypeVar("modelsModel", bound=models.Model)
|
15
|
+
|
16
|
+
|
17
|
+
def getFullCleanMethode(model: Type[models.Model]) -> Callable[..., None]:
|
18
|
+
"""
|
19
|
+
Return a custom `full_clean` method for a Django model that performs both standard validation and additional rule-based checks.
|
20
|
+
|
21
|
+
The generated method first applies Django's built-in model validation, then evaluates custom rules defined in the model's `_meta.rules` attribute. If any validation or rule fails, it raises a `ValidationError` containing all collected errors.
|
22
|
+
|
23
|
+
Parameters:
|
24
|
+
model (Type[models.Model]): The Django model class for which to generate the custom `full_clean` method.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
Callable[..., None]: A `full_clean` method that can be assigned to the model class.
|
28
|
+
"""
|
29
|
+
|
30
|
+
def full_clean(self: models.Model, *args: Any, **kwargs: Any):
|
31
|
+
"""
|
32
|
+
Performs full validation on the model instance, including both standard Django validation and custom rule-based checks.
|
33
|
+
|
34
|
+
Aggregates errors from Django's built-in validation and any additional rules defined in the model's `_meta.rules` attribute. Raises a `ValidationError` containing all collected errors if any validation or rule check fails.
|
35
|
+
"""
|
36
|
+
errors: dict[str, Any] = {}
|
37
|
+
try:
|
38
|
+
super(model, self).full_clean(*args, **kwargs) # type: ignore
|
39
|
+
except ValidationError as e:
|
40
|
+
errors.update(e.message_dict)
|
41
|
+
|
42
|
+
rules: list[Rule] = getattr(self._meta, "rules")
|
43
|
+
for rule in rules:
|
44
|
+
if not rule.evaluate(self):
|
45
|
+
error_message = rule.getErrorMessage()
|
46
|
+
if error_message:
|
47
|
+
errors.update(error_message)
|
48
|
+
|
49
|
+
if errors:
|
50
|
+
raise ValidationError(errors)
|
51
|
+
|
52
|
+
return full_clean
|
53
|
+
|
54
|
+
|
55
|
+
class GeneralManagerBasisModel(models.Model):
|
56
|
+
_general_manager_class: ClassVar[Type[GeneralManager]]
|
57
|
+
is_active = models.BooleanField(default=True)
|
58
|
+
history = HistoricalRecords(inherit=True)
|
59
|
+
|
60
|
+
class Meta:
|
61
|
+
abstract = True
|
62
|
+
|
63
|
+
|
64
|
+
class GeneralManagerModel(GeneralManagerBasisModel):
|
65
|
+
changed_by = models.ForeignKey(
|
66
|
+
settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True
|
67
|
+
)
|
68
|
+
changed_by_id: int | None
|
69
|
+
|
70
|
+
@property
|
71
|
+
def _history_user(self) -> AbstractUser | None:
|
72
|
+
"""
|
73
|
+
Returns the user who last modified this model instance, or None if no user is set.
|
74
|
+
"""
|
75
|
+
return self.changed_by
|
76
|
+
|
77
|
+
@_history_user.setter
|
78
|
+
def _history_user(self, value: AbstractUser) -> None:
|
79
|
+
"""
|
80
|
+
Set the user responsible for the most recent change to the model instance.
|
81
|
+
|
82
|
+
Parameters:
|
83
|
+
value (AbstractUser): The user to associate with the latest modification.
|
84
|
+
"""
|
85
|
+
self.changed_by = value
|
86
|
+
|
87
|
+
class Meta: # type: ignore
|
88
|
+
abstract = True
|
@@ -24,17 +24,16 @@ if TYPE_CHECKING:
|
|
24
24
|
logger = logging.getLogger(__name__)
|
25
25
|
|
26
26
|
|
27
|
-
class ReadOnlyInterface(DBBasedInterface):
|
27
|
+
class ReadOnlyInterface(DBBasedInterface[GeneralManagerBasisModel]):
|
28
28
|
_interface_type = "readonly"
|
29
|
-
_model: Type[GeneralManagerBasisModel]
|
30
29
|
_parent_class: Type[GeneralManager]
|
31
30
|
|
32
31
|
@staticmethod
|
33
32
|
def getUniqueFields(model: Type[models.Model]) -> set[str]:
|
34
33
|
"""
|
35
|
-
Return
|
34
|
+
Return a set of field names that uniquely identify instances of the specified Django model.
|
36
35
|
|
37
|
-
Considers fields marked as unique (excluding "id"), unique_together
|
36
|
+
Considers fields marked as unique (excluding "id"), as well as fields defined in `unique_together` and `UniqueConstraint` constraints.
|
38
37
|
"""
|
39
38
|
opts = model._meta
|
40
39
|
unique_fields: set[str] = set()
|
@@ -57,9 +56,9 @@ class ReadOnlyInterface(DBBasedInterface):
|
|
57
56
|
@classmethod
|
58
57
|
def syncData(cls) -> None:
|
59
58
|
"""
|
60
|
-
Synchronizes the associated Django model with
|
59
|
+
Synchronizes the associated Django model with JSON data from the parent class, ensuring the database records match the provided data exactly.
|
61
60
|
|
62
|
-
Parses the JSON data, creates or updates model instances based on unique fields, and
|
61
|
+
Parses the JSON data, creates or updates model instances based on unique fields, and deactivates any database records not present in the JSON data. Raises a ValueError if required attributes are missing, if the JSON data is invalid, or if no unique fields are defined.
|
63
62
|
"""
|
64
63
|
if cls.ensureSchemaIsUpToDate(cls._parent_class, cls._model):
|
65
64
|
logger.warning(
|
@@ -138,22 +137,18 @@ class ReadOnlyInterface(DBBasedInterface):
|
|
138
137
|
new_manager_class: Type[GeneralManager], model: Type[models.Model]
|
139
138
|
) -> list[Warning]:
|
140
139
|
"""
|
141
|
-
|
142
|
-
|
143
|
-
Parameters:
|
144
|
-
new_manager_class (Type[GeneralManager]): The manager class associated with the model.
|
145
|
-
model (Type[models.Model]): The Django model to check.
|
140
|
+
Check if the database schema for a Django model matches its model definition.
|
146
141
|
|
147
142
|
Returns:
|
148
|
-
|
143
|
+
A list of Django Warning objects describing schema issues, such as missing tables or column mismatches. Returns an empty list if the schema is up to date.
|
149
144
|
"""
|
150
145
|
|
151
146
|
def table_exists(table_name: str) -> bool:
|
152
147
|
"""
|
153
|
-
|
148
|
+
Determine whether a database table with the specified name exists.
|
154
149
|
|
155
150
|
Parameters:
|
156
|
-
table_name (str):
|
151
|
+
table_name (str): Name of the database table to check.
|
157
152
|
|
158
153
|
Returns:
|
159
154
|
bool: True if the table exists, False otherwise.
|
@@ -166,11 +161,12 @@ class ReadOnlyInterface(DBBasedInterface):
|
|
166
161
|
model: Type[models.Model], table: str
|
167
162
|
) -> tuple[list[str], list[str]]:
|
168
163
|
"""
|
169
|
-
|
164
|
+
Compares the fields of a Django model to the columns of a specified database table.
|
170
165
|
|
171
166
|
Returns:
|
172
|
-
|
173
|
-
|
167
|
+
A tuple containing two lists:
|
168
|
+
- The first list contains column names defined in the model but missing from the database table.
|
169
|
+
- The second list contains column names present in the database table but not defined in the model.
|
174
170
|
"""
|
175
171
|
with connection.cursor() as cursor:
|
176
172
|
desc = connection.introspection.get_table_description(cursor, table)
|
@@ -208,7 +204,7 @@ class ReadOnlyInterface(DBBasedInterface):
|
|
208
204
|
"""
|
209
205
|
Decorator for post-creation hooks that registers a new manager class as read-only.
|
210
206
|
|
211
|
-
After
|
207
|
+
After the wrapped post-creation function is executed, the newly created manager class is added to the meta-class's list of read-only classes, marking it as a read-only interface.
|
212
208
|
"""
|
213
209
|
|
214
210
|
def wrapper(
|
@@ -217,12 +213,9 @@ class ReadOnlyInterface(DBBasedInterface):
|
|
217
213
|
model: Type[GeneralManagerBasisModel],
|
218
214
|
):
|
219
215
|
"""
|
220
|
-
Registers
|
216
|
+
Registers a newly created manager class as read-only after executing the wrapped post-creation function.
|
221
217
|
|
222
|
-
|
223
|
-
new_class (Type[GeneralManager]): The newly created manager class to register.
|
224
|
-
interface_cls (Type[ReadOnlyInterface]): The associated read-only interface class.
|
225
|
-
model (Type[GeneralManagerModel]): The model class associated with the manager.
|
218
|
+
This function appends the new manager class to the list of read-only classes in the meta system, ensuring it is recognized as a read-only interface.
|
226
219
|
"""
|
227
220
|
from general_manager.manager.meta import GeneralManagerMeta
|
228
221
|
|
@@ -234,16 +227,28 @@ class ReadOnlyInterface(DBBasedInterface):
|
|
234
227
|
@staticmethod
|
235
228
|
def readOnlyPreCreate(func: Callable[..., Any]) -> Callable[..., Any]:
|
236
229
|
"""
|
237
|
-
Decorator for pre-creation hook functions
|
230
|
+
Decorator for pre-creation hook functions that ensures the base model class is set to `GeneralManagerBasisModel`.
|
238
231
|
|
239
|
-
Wraps a pre-creation function, injecting
|
232
|
+
Wraps a pre-creation function, injecting `GeneralManagerBasisModel` as the `base_model_class` argument before the manager class is created.
|
240
233
|
"""
|
234
|
+
|
241
235
|
def wrapper(
|
242
236
|
name: generalManagerClassName,
|
243
237
|
attrs: attributes,
|
244
238
|
interface: interfaceBaseClass,
|
245
239
|
base_model_class=GeneralManagerBasisModel,
|
246
240
|
):
|
241
|
+
"""
|
242
|
+
Wraps a function to ensure the `base_model_class` argument is set to `GeneralManagerBasisModel` before invocation.
|
243
|
+
|
244
|
+
Parameters:
|
245
|
+
name: The name of the manager class being created.
|
246
|
+
attrs: Attributes for the manager class.
|
247
|
+
interface: The interface base class to use.
|
248
|
+
|
249
|
+
Returns:
|
250
|
+
The result of calling the wrapped function with `base_model_class` set to `GeneralManagerBasisModel`.
|
251
|
+
"""
|
247
252
|
return func(
|
248
253
|
name, attrs, interface, base_model_class=GeneralManagerBasisModel
|
249
254
|
)
|
@@ -253,12 +258,14 @@ class ReadOnlyInterface(DBBasedInterface):
|
|
253
258
|
@classmethod
|
254
259
|
def handleInterface(cls) -> tuple[classPreCreationMethod, classPostCreationMethod]:
|
255
260
|
"""
|
256
|
-
Return the pre- and post-creation hook methods for integrating
|
261
|
+
Return the pre- and post-creation hook methods for integrating the interface with a manager meta-class system.
|
257
262
|
|
258
|
-
The returned tuple
|
263
|
+
The returned tuple includes:
|
264
|
+
- A pre-creation method that ensures the base model class is set for read-only operation.
|
265
|
+
- A post-creation method that registers the manager class as read-only.
|
259
266
|
|
260
267
|
Returns:
|
261
|
-
tuple:
|
268
|
+
tuple: The pre-creation and post-creation hook methods for manager class lifecycle integration.
|
262
269
|
"""
|
263
270
|
return cls.readOnlyPreCreate(cls._preCreate), cls.readOnlyPostCreate(
|
264
271
|
cls._postCreate
|