djresttoolkit 0.6.2__py3-none-any.whl → 0.8.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.
README.md CHANGED
@@ -85,7 +85,132 @@ python manage.py dbseed --count 10
85
85
  python manage.py dbseed --model User --seed 42
86
86
  ```
87
87
 
88
- ### 2. EmailSender
88
+ Here’s a **concise API reference** for your database flush management command for `djresttoolkit`:
89
+
90
+ ---
91
+
92
+ ### 2. DB Flush Command
93
+
94
+ ```python
95
+ from djresttoolkit.management.commands import flush
96
+ ```
97
+
98
+ #### `manage.py dbflush`
99
+
100
+ Command to **delete all records** from the database for all models or a specific model and **reset auto-increment IDs**.
101
+
102
+ #### Usage
103
+
104
+ ```bash
105
+ python manage.py flush [--model ModelName] [--yes]
106
+ ```
107
+
108
+ #### dbflush command options
109
+
110
+ - `--model`: Name of the model to flush (case-sensitive, e.g., `User`). If omitted, flushes all models.
111
+ - `--yes`: Skip confirmation prompt. Without this, the command asks for confirmation before deleting.
112
+
113
+ #### dbflush command behavior
114
+
115
+ - Deletes all records for the specified model or all models.
116
+ - Resets primary key sequences for supported databases:
117
+
118
+ - PostgreSQL: `ALTER SEQUENCE ... RESTART WITH 1`
119
+ - SQLite: Deletes from `sqlite_sequence` table
120
+ - Others: Logs a warning (not implemented).
121
+ - Uses transactions to ensure safe operations.
122
+
123
+ #### dbflush command example
124
+
125
+ ```bash
126
+ # Flush all models with confirmation
127
+ python manage.py dbflush
128
+
129
+ # Flush a specific model (User) with confirmation
130
+ python manage.py dbflush --model User
131
+
132
+ # Flush all models without prompt
133
+ python manage.py dbflush --yes
134
+ ```
135
+
136
+ #### Output
137
+
138
+ ```bash
139
+ Flushed 10 records from model "User" and reset IDs.
140
+ ```
141
+
142
+ or
143
+
144
+ ```bash
145
+ Flushed 120 records from all models and reset IDs.
146
+ ```
147
+
148
+ ### 3. EnvBaseSettings
149
+
150
+ ```python
151
+ from djresttoolkit.envconfig import EnvBaseSettings
152
+ ```
153
+
154
+ #### `EnvBaseSettings`
155
+
156
+ A **base settings class** for managing application configuration using:
157
+
158
+ - YAML files (default `.environ.yaml`)
159
+ - Environment variables (default `.env`)
160
+
161
+ Supports **nested configuration** using double underscores (`__`) in environment variable names.
162
+
163
+ #### Class Attributes
164
+
165
+ | Attribute | Type | Default | Description |
166
+ | -------------- | -------------------- | --------------- | ------------------------------------------------------------------ |
167
+ | `env_file` | `str` | `.env` | Environment variable file path. |
168
+ | `yaml_file` | `str` | `.environ.yaml` | YAML configuration file path. |
169
+ | `model_config` | `SettingsConfigDict` | — | Pydantic settings configuration (file encoding, nested delimiter). |
170
+
171
+ #### Methods
172
+
173
+ #### `load(cls, *, env_file: str | None = None, ymal_file: str | None = None, warning: bool = True) -> EnvBaseSettings`
174
+
175
+ Loads configuration from **YAML first**, then overrides with **environment variables**.
176
+
177
+ #### Parameters
178
+
179
+ - `env_file` — Optional custom `.env` file path.
180
+ - `ymal_file` — Optional custom YAML file path.
181
+ - `warning` — Emit a warning if YAML file is missing (default `True`).
182
+
183
+ #### Returns
184
+
185
+ - Instance of `EnvBaseSettings` (or subclass) with loaded configuration.
186
+
187
+ #### Raises
188
+
189
+ - `UserWarning` if YAML file not found and `warning=True`.
190
+
191
+ ### Usage Example
192
+
193
+ ```python
194
+ from djresttoolkit.envconfig import EnvBaseSettings
195
+
196
+ class EnvSettings(EnvBaseSettings):
197
+ debug: bool = False
198
+ database_url: str
199
+
200
+ # Load settings
201
+ settings = EnvSettings.load(warning=False)
202
+
203
+ print(settings.debug)
204
+ print(settings.database_url)
205
+ ```
206
+
207
+ #### Features
208
+
209
+ - Prioritizes `.env` variables over YAML.
210
+ - Supports nested keys: `DATABASE__HOST` → `settings.database.host`.
211
+ - Designed to be subclassed for project-specific settings.
212
+
213
+ ### 4. EmailSender
89
214
 
90
215
  ```python
91
216
  from djresttoolkit.mail import EmailSender, EmailContent, EmailTemplate
@@ -101,7 +226,7 @@ Send templated emails.
101
226
  EmailSender(email_content: EmailContent | EmailContentDict)
102
227
  ```
103
228
 
104
- #### Methods
229
+ #### EmailSender Methods
105
230
 
106
231
  ```python
107
232
  send(to: list[str], exceptions: bool = False) -> bool
@@ -134,7 +259,7 @@ EmailSender(content).send(to=["user@example.com"])
134
259
 
135
260
  - `text`, `html` — template file paths
136
261
 
137
- ### 3. Custom DRF Exception Handler
262
+ ### 5. Custom DRF Exception Handler
138
263
 
139
264
  ```python
140
265
  from djresttoolkit.views import exception_handler
@@ -148,12 +273,12 @@ A DRF exception handler that:
148
273
  - Adds throttling support (defaults to `AnonRateThrottle`).
149
274
  - Returns **429 Too Many Requests** with `retry_after` if throttle limit is exceeded.
150
275
 
151
- #### Parameters
276
+ #### Exception Handler Parameters
152
277
 
153
278
  - `exc`: Exception object.
154
279
  - `context`: DRF context dictionary containing `"request"` and `"view"`.
155
280
 
156
- #### Returns
281
+ #### Returns Type of Exception Handler
157
282
 
158
283
  - `Response` — DRF Response object (with throttling info if applicable), or `None`.
159
284
 
@@ -174,7 +299,7 @@ REST_FRAMEWORK = {
174
299
  - Tracks requests in cache and calculates `retry_after`.
175
300
  - Cleans expired timestamps automatically.
176
301
 
177
- ### 4. Response Time Middleware
302
+ ### 6. Response Time Middleware
178
303
 
179
304
  ```python
180
305
  from djresttoolkit.middlewares import ResponseTimeMiddleware
@@ -192,7 +317,7 @@ ResponseTimeMiddleware(get_response: Callable[[HttpRequest], HttpResponse])
192
317
 
193
318
  - `get_response`: The next middleware or view callable.
194
319
 
195
- #### Usage
320
+ #### Response Time Middleware Usage
196
321
 
197
322
  Add it to your Django `MIDDLEWARE` in `settings.py`:
198
323
 
@@ -221,7 +346,7 @@ X-Response-Time: 0.01234 seconds
221
346
  INFO: Request processed in 0.01234 seconds
222
347
  ```
223
348
 
224
- ### 5. Throttle Utilities
349
+ ### 7. Throttle Utilities
225
350
 
226
351
  #### `ThrottleInfoJSONRenderer`
227
352
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: djresttoolkit
3
- Version: 0.6.2
3
+ Version: 0.8.0
4
4
  Summary: A collection of Django and DRF utilities to simplify API development.
5
5
  Project-URL: Homepage, https://github.com/shaileshpandit141/djresttoolkit
6
6
  Project-URL: Documentation, https://shaileshpandit141.github.io/djresttoolkit
@@ -47,7 +47,9 @@ Classifier: Topic :: Utilities
47
47
  Classifier: Typing :: Typed
48
48
  Requires-Python: >=3.13
49
49
  Requires-Dist: faker>=37.5.3
50
+ Requires-Dist: pydantic-settings>=2.10.1
50
51
  Requires-Dist: pydantic>=2.11.7
52
+ Requires-Dist: pyyaml>=6.0.2
51
53
  Provides-Extra: dev
52
54
  Requires-Dist: mypy; extra == 'dev'
53
55
  Requires-Dist: pytest; extra == 'dev'
@@ -141,7 +143,132 @@ python manage.py dbseed --count 10
141
143
  python manage.py dbseed --model User --seed 42
142
144
  ```
143
145
 
144
- ### 2. EmailSender
146
+ Here’s a **concise API reference** for your database flush management command for `djresttoolkit`:
147
+
148
+ ---
149
+
150
+ ### 2. DB Flush Command
151
+
152
+ ```python
153
+ from djresttoolkit.management.commands import flush
154
+ ```
155
+
156
+ #### `manage.py dbflush`
157
+
158
+ Command to **delete all records** from the database for all models or a specific model and **reset auto-increment IDs**.
159
+
160
+ #### Usage
161
+
162
+ ```bash
163
+ python manage.py flush [--model ModelName] [--yes]
164
+ ```
165
+
166
+ #### dbflush command options
167
+
168
+ - `--model`: Name of the model to flush (case-sensitive, e.g., `User`). If omitted, flushes all models.
169
+ - `--yes`: Skip confirmation prompt. Without this, the command asks for confirmation before deleting.
170
+
171
+ #### dbflush command behavior
172
+
173
+ - Deletes all records for the specified model or all models.
174
+ - Resets primary key sequences for supported databases:
175
+
176
+ - PostgreSQL: `ALTER SEQUENCE ... RESTART WITH 1`
177
+ - SQLite: Deletes from `sqlite_sequence` table
178
+ - Others: Logs a warning (not implemented).
179
+ - Uses transactions to ensure safe operations.
180
+
181
+ #### dbflush command example
182
+
183
+ ```bash
184
+ # Flush all models with confirmation
185
+ python manage.py dbflush
186
+
187
+ # Flush a specific model (User) with confirmation
188
+ python manage.py dbflush --model User
189
+
190
+ # Flush all models without prompt
191
+ python manage.py dbflush --yes
192
+ ```
193
+
194
+ #### Output
195
+
196
+ ```bash
197
+ Flushed 10 records from model "User" and reset IDs.
198
+ ```
199
+
200
+ or
201
+
202
+ ```bash
203
+ Flushed 120 records from all models and reset IDs.
204
+ ```
205
+
206
+ ### 3. EnvBaseSettings
207
+
208
+ ```python
209
+ from djresttoolkit.envconfig import EnvBaseSettings
210
+ ```
211
+
212
+ #### `EnvBaseSettings`
213
+
214
+ A **base settings class** for managing application configuration using:
215
+
216
+ - YAML files (default `.environ.yaml`)
217
+ - Environment variables (default `.env`)
218
+
219
+ Supports **nested configuration** using double underscores (`__`) in environment variable names.
220
+
221
+ #### Class Attributes
222
+
223
+ | Attribute | Type | Default | Description |
224
+ | -------------- | -------------------- | --------------- | ------------------------------------------------------------------ |
225
+ | `env_file` | `str` | `.env` | Environment variable file path. |
226
+ | `yaml_file` | `str` | `.environ.yaml` | YAML configuration file path. |
227
+ | `model_config` | `SettingsConfigDict` | — | Pydantic settings configuration (file encoding, nested delimiter). |
228
+
229
+ #### Methods
230
+
231
+ #### `load(cls, *, env_file: str | None = None, ymal_file: str | None = None, warning: bool = True) -> EnvBaseSettings`
232
+
233
+ Loads configuration from **YAML first**, then overrides with **environment variables**.
234
+
235
+ #### Parameters
236
+
237
+ - `env_file` — Optional custom `.env` file path.
238
+ - `ymal_file` — Optional custom YAML file path.
239
+ - `warning` — Emit a warning if YAML file is missing (default `True`).
240
+
241
+ #### Returns
242
+
243
+ - Instance of `EnvBaseSettings` (or subclass) with loaded configuration.
244
+
245
+ #### Raises
246
+
247
+ - `UserWarning` if YAML file not found and `warning=True`.
248
+
249
+ ### Usage Example
250
+
251
+ ```python
252
+ from djresttoolkit.envconfig import EnvBaseSettings
253
+
254
+ class EnvSettings(EnvBaseSettings):
255
+ debug: bool = False
256
+ database_url: str
257
+
258
+ # Load settings
259
+ settings = EnvSettings.load(warning=False)
260
+
261
+ print(settings.debug)
262
+ print(settings.database_url)
263
+ ```
264
+
265
+ #### Features
266
+
267
+ - Prioritizes `.env` variables over YAML.
268
+ - Supports nested keys: `DATABASE__HOST` → `settings.database.host`.
269
+ - Designed to be subclassed for project-specific settings.
270
+
271
+ ### 4. EmailSender
145
272
 
146
273
  ```python
147
274
  from djresttoolkit.mail import EmailSender, EmailContent, EmailTemplate
@@ -157,7 +284,7 @@ Send templated emails.
157
284
  EmailSender(email_content: EmailContent | EmailContentDict)
158
285
  ```
159
286
 
160
- #### Methods
287
+ #### EmailSender Methods
161
288
 
162
289
  ```python
163
290
  send(to: list[str], exceptions: bool = False) -> bool
@@ -190,7 +317,7 @@ EmailSender(content).send(to=["user@example.com"])
190
317
 
191
318
  - `text`, `html` — template file paths
192
319
 
193
- ### 3. Custom DRF Exception Handler
320
+ ### 5. Custom DRF Exception Handler
194
321
 
195
322
  ```python
196
323
  from djresttoolkit.views import exception_handler
@@ -204,12 +331,12 @@ A DRF exception handler that:
204
331
  - Adds throttling support (defaults to `AnonRateThrottle`).
205
332
  - Returns **429 Too Many Requests** with `retry_after` if throttle limit is exceeded.
206
333
 
207
- #### Parameters
334
+ #### Exception Handler Parameters
208
335
 
209
336
  - `exc`: Exception object.
210
337
  - `context`: DRF context dictionary containing `"request"` and `"view"`.
211
338
 
212
- #### Returns
339
+ #### Returns Type of Exception Handler
213
340
 
214
341
  - `Response` — DRF Response object (with throttling info if applicable), or `None`.
215
342
 
@@ -230,7 +357,7 @@ REST_FRAMEWORK = {
230
357
  - Tracks requests in cache and calculates `retry_after`.
231
358
  - Cleans expired timestamps automatically.
232
359
 
233
- ### 4. Response Time Middleware
360
+ ### 6. Response Time Middleware
234
361
 
235
362
  ```python
236
363
  from djresttoolkit.middlewares import ResponseTimeMiddleware
@@ -248,7 +375,7 @@ ResponseTimeMiddleware(get_response: Callable[[HttpRequest], HttpResponse])
248
375
 
249
376
  - `get_response`: The next middleware or view callable.
250
377
 
251
- #### Usage
378
+ #### Response Time Middleware Usage
252
379
 
253
380
  Add it to your Django `MIDDLEWARE` in `settings.py`:
254
381
 
@@ -277,7 +404,7 @@ X-Response-Time: 0.01234 seconds
277
404
  INFO: Request processed in 0.01234 seconds
278
405
  ```
279
406
 
280
- ### 5. Throttle Utilities
407
+ ### 7. Throttle Utilities
281
408
 
282
409
  #### `ThrottleInfoJSONRenderer`
283
410
 
@@ -1,20 +1,24 @@
1
1
  LICENSE,sha256=8-oZM3yuuTRjySMbVKX9YXYA7Y4M_KhQNBYXPFjeWUo,1074
2
- README.md,sha256=q-R5E_ZZPZt6vLW4TL-HA8M601_vQrI53IZ-dIAgD9E,6983
2
+ README.md,sha256=9S8AiRr4U5uA-YrgtQbUZiYpbg4rT_UejlDGhJ2WYzM,10558
3
3
  demo/staticfiles/admin/img/LICENSE,sha256=0RT6_zSIwWwxmzI13EH5AjnT1j2YU3MwM9j3U19cAAQ,1081
4
4
  src/djresttoolkit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  src/djresttoolkit/admin.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  src/djresttoolkit/apps.py,sha256=nKb5GUIEhAB3IL3lTmEXNc5XuvvaZupH-1CCuYKFrEQ,158
7
7
  src/djresttoolkit/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  src/djresttoolkit/dbseed/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
- src/djresttoolkit/dbseed/models/__init__.py,sha256=B2WJqw2ncqf5nNhkM3XDFx13oNg2ccsULUQkFAjOyrY,105
9
+ src/djresttoolkit/dbseed/models/__init__.py,sha256=uuynQIcfVqEaZN9hF_caI24zm8az23JdXLDrv7xOKTQ,180
10
+ src/djresttoolkit/dbseed/models/_choice_field.py,sha256=T7LAzbyXqlYp2mtCAKL8E1Da_MEh9RzgLZrFJ7fa4gM,446
10
11
  src/djresttoolkit/dbseed/models/_gen.py,sha256=qBPQaLvh1rcEam0YmE4JBJqpa-Vv5IFlIIagkEMHDVw,206
11
12
  src/djresttoolkit/dbseed/models/_seed_model.py,sha256=0cmbi0VNKjmJbwhjeCFsvb3iKYjok6TJOk6Y2MF_3N4,2443
13
+ src/djresttoolkit/envconfig/__init__.py,sha256=PcLaPaVfQmz3-4m6SwoOQF2W4U7F0agBGJ4Qjqbcyfw,74
14
+ src/djresttoolkit/envconfig/_env_settings.py,sha256=cKGDLo7WU0wzQGkWSwgrUxGCb0sT111JUt4HGlDVSxo,3221
12
15
  src/djresttoolkit/mail/__init__.py,sha256=tB9SdMlhfWQ640q4aobZ0H1c7fTWalpDL2I-onkr2VI,268
13
16
  src/djresttoolkit/mail/_email_sender.py,sha256=bPMqgD5HibJcOZgO6xxHOhdK9HEhnGNC6BoMPpo-h7k,3096
14
17
  src/djresttoolkit/mail/_models.py,sha256=of5KsLGvsN2OWgDYgdtLEijulg817TXgsLKuUdsnDQc,1447
15
18
  src/djresttoolkit/mail/_types.py,sha256=zf6CcXR1ei_UmZ1nLAJa378OAJ6ftnBICqEOkzXPNw8,646
16
19
  src/djresttoolkit/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
20
  src/djresttoolkit/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
+ src/djresttoolkit/management/commands/dbflush.py,sha256=v7rXcuNQDiXLV7p0xzKMNXVeWAN7QKmq2qQQAbhHEEw,3423
18
22
  src/djresttoolkit/management/commands/dbseed.py,sha256=sY87TvvzECG7aQXxsDjr45VzCzJpofLacBK49EYFK8M,4225
19
23
  src/djresttoolkit/middlewares/__init__.py,sha256=GZHU3Yy4xXoEi62tHn0UJNxN6XgGM2_HES8Bt5AS5Lk,100
20
24
  src/djresttoolkit/middlewares/_response_time_middleware.py,sha256=1wCwdkW5Ng6HJo8zx0F7ylms84OGP-1K0kbyG6Vacuk,908
@@ -27,8 +31,8 @@ src/djresttoolkit/throttling/_throttle_inspector.py,sha256=Kss6ZxKy-EXq9UGaGprGD
27
31
  src/djresttoolkit/views/__init__.py,sha256=XrxBrs6sH4HmUzp41omcmy_y94pSaXAVn01ttQ022-4,76
28
32
  src/djresttoolkit/views/_exceptions/__init__.py,sha256=DrCUxuPNyBR4WhzNutn5HDxLa--q51ykIxSG7_bFsOI,83
29
33
  src/djresttoolkit/views/_exceptions/_exception_handler.py,sha256=_o7If47bzWLl57LeSXSWsIDsJGo2RIpwYAwNQ-hsHVY,2839
30
- djresttoolkit-0.6.2.dist-info/METADATA,sha256=oeLct3kUn0oN2t0SYWXTp-XYRURhNaAcHi7srpU9mE4,9922
31
- djresttoolkit-0.6.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
32
- djresttoolkit-0.6.2.dist-info/entry_points.txt,sha256=YMhfTF-7mYppO8QqqWnvR_hyMWvoYxD6XI94_ViFu3k,60
33
- djresttoolkit-0.6.2.dist-info/licenses/LICENSE,sha256=8-oZM3yuuTRjySMbVKX9YXYA7Y4M_KhQNBYXPFjeWUo,1074
34
- djresttoolkit-0.6.2.dist-info/RECORD,,
34
+ djresttoolkit-0.8.0.dist-info/METADATA,sha256=qCwxDQnmpbQygUL7gytkkO826sOs9Zm8Xy_NXmlLvQY,13567
35
+ djresttoolkit-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
36
+ djresttoolkit-0.8.0.dist-info/entry_points.txt,sha256=YMhfTF-7mYppO8QqqWnvR_hyMWvoYxD6XI94_ViFu3k,60
37
+ djresttoolkit-0.8.0.dist-info/licenses/LICENSE,sha256=8-oZM3yuuTRjySMbVKX9YXYA7Y4M_KhQNBYXPFjeWUo,1074
38
+ djresttoolkit-0.8.0.dist-info/RECORD,,
@@ -1,4 +1,10 @@
1
1
  from ._gen import Field, Gen
2
2
  from ._seed_model import SeedModel
3
+ from ._choice_field import choice_field
3
4
 
4
- __all__ = ["SeedModel", "Gen", "Field"]
5
+ __all__ = [
6
+ "SeedModel",
7
+ "Gen",
8
+ "Field",
9
+ "choice_field",
10
+ ]
@@ -0,0 +1,17 @@
1
+ import random
2
+
3
+ from pydantic import Field
4
+
5
+
6
+ def choice_field[T](choices: list[T]) -> T:
7
+ """
8
+ Creates a field with a default value randomly selected from the provided choices.
9
+ Args:
10
+ choices (list[T]): A list of possible values for the field.
11
+ Returns:
12
+ T: A field with a default value randomly chosen from the given choices.
13
+ """
14
+
15
+ return Field(
16
+ default_factory=lambda: random.choice(seq=choices),
17
+ )
@@ -0,0 +1,3 @@
1
+ from ._env_settings import EnvBaseSettings
2
+
3
+ __all__ = ["EnvBaseSettings"]
@@ -0,0 +1,84 @@
1
+ import warnings
2
+ from pathlib import Path
3
+ from typing import Any, ClassVar
4
+
5
+ import yaml
6
+ from pydantic_settings import BaseSettings, SettingsConfigDict
7
+
8
+
9
+ class EnvBaseSettings(BaseSettings):
10
+ """ "
11
+ EnvBaseSettings is a base settings class for managing application configuration
12
+ using both YAML files and environment variables.
13
+ This class is designed to load configuration values from a YAML file first,
14
+ and then override those values with environment variables if present. It supports
15
+ nested configuration using a double underscore (`__`) as the delimiter in
16
+ environment variable names, allowing for hierarchical settings.
17
+
18
+ Class Attributes:
19
+ env_file (str): The default filename for the environment variables file (default: ".env").
20
+ yaml_file (str): The default filename for the YAML configuration file (default: ".environ.yaml").
21
+ model_config (SettingsConfigDict): Configuration for environment variable parsing, including file encoding and nested delimiter.
22
+
23
+ Methods:
24
+ load(cls, *, env_file: str | None = None, ymal_file: str | None = None, warning: bool = True) -> "EnvBaseSettings":
25
+ Loads configuration from a YAML file (if it exists), then overrides with environment variables.
26
+ - env_file: Optional custom path to the .env file.
27
+ - ymal_file: Optional custom path to the YAML file.
28
+ - warning: If True, emits a warning if the YAML file is not found.
29
+ Returns an instance of EnvBaseSettings with the loaded configuration.
30
+
31
+ Usage:
32
+ - Define your settings as subclasses of EnvBaseSettings.
33
+ - Call `YourSettingsClass.load()` to load configuration from files and environment variables.
34
+ - Supports nested configuration via double underscore in environment variable names (e.g., `DATABASE__HOST`).
35
+
36
+ Raises:
37
+ - UserWarning: If the YAML file is not found and `warning` is True.
38
+
39
+ Example:
40
+ ```python
41
+ from djresttoolkit.envconfig import EnvBaseSettings
42
+
43
+ class EnvSettings(EnvBaseSettings):
44
+ debug: bool = False
45
+ database_url: str
46
+
47
+ settings = EnvSettings.load(warning=False)
48
+ ```
49
+
50
+ """
51
+
52
+ env_file: ClassVar[str] = ".env"
53
+ yaml_file: ClassVar[str] = ".environ.yaml"
54
+
55
+ model_config = SettingsConfigDict(
56
+ env_file=env_file,
57
+ env_file_encoding="utf-8",
58
+ env_nested_delimiter="__",
59
+ )
60
+
61
+ @classmethod
62
+ def load(
63
+ cls,
64
+ *,
65
+ env_file: str | None = None,
66
+ ymal_file: str | None = None,
67
+ warning: bool = True,
68
+ ) -> "EnvBaseSettings":
69
+ """Load from YAML first, then override with .env."""
70
+ if env_file:
71
+ cls.env_file = env_file
72
+ if ymal_file:
73
+ cls.yaml_file = ymal_file
74
+
75
+ config_file = Path(cls.yaml_file)
76
+ yaml_data: dict[str, Any] = {}
77
+ if config_file.exists():
78
+ with config_file.open("r") as f:
79
+ yaml_data = yaml.safe_load(f) or {}
80
+ elif warning:
81
+ msg: str = f"Config file {config_file} not found, using only env vars."
82
+ warnings.warn(msg, UserWarning, stacklevel=1)
83
+
84
+ return cls(**yaml_data)
@@ -0,0 +1,94 @@
1
+ from typing import Any
2
+
3
+ from django.apps import apps
4
+ from django.core.management.base import BaseCommand, CommandError, CommandParser
5
+ from django.db import connection, transaction
6
+
7
+
8
+ class Command(BaseCommand):
9
+ help = "Flush database records for all models or a specific model"
10
+
11
+ def add_arguments(self, parser: CommandParser) -> None:
12
+ parser.add_argument(
13
+ "--model",
14
+ type=str,
15
+ help="Specify the model name to flush records (case-sensitive, e.g., User)",
16
+ )
17
+ parser.add_argument(
18
+ "--yes",
19
+ action="store_true",
20
+ help="Confirm flush without prompt",
21
+ )
22
+
23
+ def handle(self, *args: Any, **options: Any) -> None:
24
+ """Handle the flushing of database records and reset IDs."""
25
+
26
+ model_name = options.get("model")
27
+ confirm = options.get("yes", False)
28
+
29
+ if not confirm:
30
+ prompt = "Are you sure you want to flush "
31
+ prompt += f"the model '{model_name}'" if model_name else "all models"
32
+ prompt += "? [y/n]: "
33
+ user_input = input(prompt)
34
+ if user_input.lower() not in ["y", "yes"]:
35
+ self.stdout.write(self.style.WARNING("Operation cancelled."))
36
+ return
37
+
38
+ def reset_sequence(table_name: str) -> None:
39
+ """Reset auto-increment ID sequence for supported databases."""
40
+ with connection.cursor() as cursor:
41
+ if connection.vendor == "postgresql":
42
+ cursor.execute(
43
+ f'ALTER SEQUENCE "{table_name}_id_seq" RESTART WITH 1;'
44
+ )
45
+ elif connection.vendor == "sqlite":
46
+ cursor.execute(
47
+ f"DELETE FROM sqlite_sequence WHERE name='{table_name}';"
48
+ )
49
+ else:
50
+ self.stdout.write(
51
+ self.style.WARNING(
52
+ f"ID reset not implemented for {connection.vendor}."
53
+ )
54
+ )
55
+
56
+ if model_name:
57
+ # Find the model automatically across all apps
58
+ model = None
59
+ for m in apps.get_models():
60
+ if m.__name__ == model_name:
61
+ model = m
62
+ break
63
+
64
+ if not model:
65
+ raise CommandError(
66
+ f'Model "{model_name}" not found in any installed app.'
67
+ )
68
+
69
+ table_name = model._meta.db_table
70
+ with transaction.atomic():
71
+ deleted_count, _ = model.objects.all().delete()
72
+ reset_sequence(table_name)
73
+
74
+ self.stdout.write(
75
+ self.style.SUCCESS(
76
+ f'Flushed {deleted_count} records from model "{model_name}" and reset IDs.'
77
+ )
78
+ )
79
+
80
+ else:
81
+ # Flush all models
82
+ total_deleted = 0
83
+ with transaction.atomic():
84
+ for model in apps.get_models():
85
+ table_name = model._meta.db_table
86
+ deleted_count, _ = model.objects.all().delete()
87
+ total_deleted += deleted_count
88
+ reset_sequence(table_name)
89
+
90
+ self.stdout.write(
91
+ self.style.SUCCESS(
92
+ f"Flushed {total_deleted} records from all models and reset IDs."
93
+ )
94
+ )