turbodrf 0.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.
- turbodrf-0.1.0/API.md +472 -0
- turbodrf-0.1.0/CONTRIBUTING.md +409 -0
- turbodrf-0.1.0/DEPLOYMENT.md +218 -0
- turbodrf-0.1.0/INSTALL.md +280 -0
- turbodrf-0.1.0/LICENSE +21 -0
- turbodrf-0.1.0/MANIFEST.in +27 -0
- turbodrf-0.1.0/PKG-INFO +1569 -0
- turbodrf-0.1.0/README.md +1519 -0
- turbodrf-0.1.0/pyproject.toml +100 -0
- turbodrf-0.1.0/setup.cfg +4 -0
- turbodrf-0.1.0/setup.py +58 -0
- turbodrf-0.1.0/tests/__init__.py +7 -0
- turbodrf-0.1.0/tests/fixtures.py +207 -0
- turbodrf-0.1.0/tests/integration/__init__.py +0 -0
- turbodrf-0.1.0/tests/integration/test_api_endpoints.py +329 -0
- turbodrf-0.1.0/tests/integration/test_role_permissions.py +320 -0
- turbodrf-0.1.0/tests/settings.py +186 -0
- turbodrf-0.1.0/tests/test_app/__init__.py +0 -0
- turbodrf-0.1.0/tests/test_app/apps.py +26 -0
- turbodrf-0.1.0/tests/test_app/models.py +108 -0
- turbodrf-0.1.0/tests/test_package.py +71 -0
- turbodrf-0.1.0/tests/test_runner.py +31 -0
- turbodrf-0.1.0/tests/unit/__init__.py +0 -0
- turbodrf-0.1.0/tests/unit/test_custom_viewsets.py +296 -0
- turbodrf-0.1.0/tests/unit/test_default_permissions.py +148 -0
- turbodrf-0.1.0/tests/unit/test_mixins.py +118 -0
- turbodrf-0.1.0/tests/unit/test_permissions.py +173 -0
- turbodrf-0.1.0/tests/unit/test_router.py +129 -0
- turbodrf-0.1.0/tests/unit/test_serializers.py +261 -0
- turbodrf-0.1.0/tests/unit/test_views.py +218 -0
- turbodrf-0.1.0/tests/urls.py +24 -0
- turbodrf-0.1.0/tox.ini +31 -0
- turbodrf-0.1.0/turbodrf/__init__.py +55 -0
- turbodrf-0.1.0/turbodrf/apps.py +15 -0
- turbodrf-0.1.0/turbodrf/documentation.py +94 -0
- turbodrf-0.1.0/turbodrf/filters.py +64 -0
- turbodrf-0.1.0/turbodrf/metadata.py +110 -0
- turbodrf-0.1.0/turbodrf/mixins.py +160 -0
- turbodrf-0.1.0/turbodrf/permissions.py +181 -0
- turbodrf-0.1.0/turbodrf/router.py +101 -0
- turbodrf-0.1.0/turbodrf/serializers.py +511 -0
- turbodrf-0.1.0/turbodrf/settings.py +26 -0
- turbodrf-0.1.0/turbodrf/swagger.py +269 -0
- turbodrf-0.1.0/turbodrf/swagger_ui.py +6 -0
- turbodrf-0.1.0/turbodrf/urls.py +29 -0
- turbodrf-0.1.0/turbodrf/user_extensions.py +51 -0
- turbodrf-0.1.0/turbodrf/utils.py +65 -0
- turbodrf-0.1.0/turbodrf/views.py +455 -0
- turbodrf-0.1.0/turbodrf.egg-info/PKG-INFO +1569 -0
- turbodrf-0.1.0/turbodrf.egg-info/SOURCES.txt +51 -0
- turbodrf-0.1.0/turbodrf.egg-info/dependency_links.txt +1 -0
- turbodrf-0.1.0/turbodrf.egg-info/requires.txt +13 -0
- turbodrf-0.1.0/turbodrf.egg-info/top_level.txt +1 -0
turbodrf-0.1.0/API.md
ADDED
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
# TurboDRF API Reference
|
|
2
|
+
|
|
3
|
+
This document provides a comprehensive API reference for TurboDRF.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Core Components](#core-components)
|
|
8
|
+
- [TurboDRFMixin](#turbodrfmixin)
|
|
9
|
+
- [TurboDRFRouter](#turbodrfrouter)
|
|
10
|
+
- [TurboDRFViewSet](#turbodrfviewset)
|
|
11
|
+
- [TurboDRFPermission](#turbodrfpermission)
|
|
12
|
+
- [TurboDRFSerializer](#turbodrfserializer)
|
|
13
|
+
- [Configuration](#configuration)
|
|
14
|
+
- [Model Configuration](#model-configuration)
|
|
15
|
+
- [Settings](#settings)
|
|
16
|
+
- [API Endpoints](#api-endpoints)
|
|
17
|
+
- [Query Parameters](#query-parameters)
|
|
18
|
+
- [Response Formats](#response-formats)
|
|
19
|
+
- [Error Handling](#error-handling)
|
|
20
|
+
|
|
21
|
+
## Core Components
|
|
22
|
+
|
|
23
|
+
### TurboDRFMixin
|
|
24
|
+
|
|
25
|
+
The core mixin that enables automatic API generation for Django models.
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
from turbodrf import TurboDRFMixin
|
|
29
|
+
|
|
30
|
+
class MyModel(models.Model, TurboDRFMixin):
|
|
31
|
+
# Model fields
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def turbodrf(cls):
|
|
35
|
+
return {
|
|
36
|
+
'fields': ['field1', 'field2'],
|
|
37
|
+
'endpoint': 'custom-endpoint', # Optional
|
|
38
|
+
'enabled': True # Optional
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Methods
|
|
43
|
+
|
|
44
|
+
##### `turbodrf()`
|
|
45
|
+
|
|
46
|
+
**Type**: `@classmethod`
|
|
47
|
+
|
|
48
|
+
**Returns**: `dict`
|
|
49
|
+
|
|
50
|
+
Configuration method that defines how the model should be exposed in the API.
|
|
51
|
+
|
|
52
|
+
**Configuration Options**:
|
|
53
|
+
|
|
54
|
+
| Key | Type | Default | Description |
|
|
55
|
+
|-----|------|---------|-------------|
|
|
56
|
+
| `fields` | `list`, `dict`, or `str` | `'__all__'` | Fields to expose in API |
|
|
57
|
+
| `endpoint` | `str` | `'{model_name}s'` | Custom endpoint name |
|
|
58
|
+
| `enabled` | `bool` | `True` | Whether to enable API for this model |
|
|
59
|
+
|
|
60
|
+
**Field Configuration Examples**:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
# Simple list (same fields for list and detail)
|
|
64
|
+
'fields': ['title', 'author', 'price']
|
|
65
|
+
|
|
66
|
+
# Different fields for list vs detail
|
|
67
|
+
'fields': {
|
|
68
|
+
'list': ['title', 'author'],
|
|
69
|
+
'detail': ['title', 'author', 'description', 'price']
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
# All fields
|
|
73
|
+
'fields': '__all__'
|
|
74
|
+
|
|
75
|
+
# Nested fields
|
|
76
|
+
'fields': ['title', 'author__name', 'category__parent__name']
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
##### `get_api_fields(view_type='list')`
|
|
80
|
+
|
|
81
|
+
**Type**: `@classmethod`
|
|
82
|
+
|
|
83
|
+
**Parameters**:
|
|
84
|
+
- `view_type` (str): Either 'list' or 'detail'
|
|
85
|
+
|
|
86
|
+
**Returns**: `list`
|
|
87
|
+
|
|
88
|
+
Get the fields for a specific view type based on the model's configuration.
|
|
89
|
+
|
|
90
|
+
##### `get_field_type(field_path)`
|
|
91
|
+
|
|
92
|
+
**Type**: `@classmethod`
|
|
93
|
+
|
|
94
|
+
**Parameters**:
|
|
95
|
+
- `field_path` (str): Field path using double-underscore notation
|
|
96
|
+
|
|
97
|
+
**Returns**: `Field` or `None`
|
|
98
|
+
|
|
99
|
+
Resolve field type for nested fields.
|
|
100
|
+
|
|
101
|
+
### TurboDRFRouter
|
|
102
|
+
|
|
103
|
+
Automatic router that discovers and registers all TurboDRF-enabled models.
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from turbodrf import TurboDRFRouter
|
|
107
|
+
|
|
108
|
+
router = TurboDRFRouter()
|
|
109
|
+
# No manual registration needed!
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
#### Methods
|
|
113
|
+
|
|
114
|
+
##### `__init__(*args, **kwargs)`
|
|
115
|
+
|
|
116
|
+
Initialize the router and automatically discover all models.
|
|
117
|
+
|
|
118
|
+
**Parameters**: Same as DRF's `DefaultRouter`
|
|
119
|
+
|
|
120
|
+
##### `discover_models()`
|
|
121
|
+
|
|
122
|
+
Automatically discover and register all models with TurboDRFMixin.
|
|
123
|
+
|
|
124
|
+
Called automatically during initialization.
|
|
125
|
+
|
|
126
|
+
### TurboDRFViewSet
|
|
127
|
+
|
|
128
|
+
Base ViewSet class for all auto-generated APIs.
|
|
129
|
+
|
|
130
|
+
#### Features
|
|
131
|
+
|
|
132
|
+
- Automatic serializer generation
|
|
133
|
+
- Built-in pagination
|
|
134
|
+
- Search, filter, and ordering support
|
|
135
|
+
- Query optimization
|
|
136
|
+
- Permission handling
|
|
137
|
+
|
|
138
|
+
#### Properties
|
|
139
|
+
|
|
140
|
+
| Property | Type | Description |
|
|
141
|
+
|----------|------|-------------|
|
|
142
|
+
| `model` | `Model` | The Django model class |
|
|
143
|
+
| `permission_classes` | `list` | `[TurboDRFPermission]` |
|
|
144
|
+
| `pagination_class` | `class` | `TurboDRFPagination` |
|
|
145
|
+
| `filter_backends` | `list` | DjangoFilter, Search, Ordering |
|
|
146
|
+
| `search_fields` | `list` | From model's `searchable_fields` |
|
|
147
|
+
| `ordering_fields` | `str` | `'__all__'` |
|
|
148
|
+
| `filterset_fields` | `str` | `'__all__'` |
|
|
149
|
+
|
|
150
|
+
### TurboDRFPermission
|
|
151
|
+
|
|
152
|
+
Role-based permission class.
|
|
153
|
+
|
|
154
|
+
#### Permission Format
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
app_label.model_name.action
|
|
158
|
+
app_label.model_name.field_name.read
|
|
159
|
+
app_label.model_name.field_name.write
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### Methods
|
|
163
|
+
|
|
164
|
+
##### `has_permission(request, view)`
|
|
165
|
+
|
|
166
|
+
Check if user has permission to perform the requested action.
|
|
167
|
+
|
|
168
|
+
**Returns**: `bool`
|
|
169
|
+
|
|
170
|
+
### TurboDRFSerializer
|
|
171
|
+
|
|
172
|
+
Base serializer with support for nested field notation.
|
|
173
|
+
|
|
174
|
+
#### Features
|
|
175
|
+
|
|
176
|
+
- Automatic handling of nested fields
|
|
177
|
+
- Dynamic field inclusion based on configuration
|
|
178
|
+
- Support for `field__subfield` notation
|
|
179
|
+
|
|
180
|
+
## Configuration
|
|
181
|
+
|
|
182
|
+
### Model Configuration
|
|
183
|
+
|
|
184
|
+
#### Basic Example
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
class Book(models.Model, TurboDRFMixin):
|
|
188
|
+
title = models.CharField(max_length=200)
|
|
189
|
+
author = models.ForeignKey(Author, on_delete=models.CASCADE)
|
|
190
|
+
price = models.DecimalField(max_digits=10, decimal_places=2)
|
|
191
|
+
|
|
192
|
+
# Enable search
|
|
193
|
+
searchable_fields = ['title', 'author__name']
|
|
194
|
+
|
|
195
|
+
@classmethod
|
|
196
|
+
def turbodrf(cls):
|
|
197
|
+
return {
|
|
198
|
+
'fields': ['title', 'author__name', 'price']
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### Advanced Example
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
class Product(models.Model, TurboDRFMixin):
|
|
206
|
+
name = models.CharField(max_length=200)
|
|
207
|
+
description = models.TextField()
|
|
208
|
+
category = models.ForeignKey(Category, on_delete=models.CASCADE)
|
|
209
|
+
price = models.DecimalField(max_digits=10, decimal_places=2)
|
|
210
|
+
|
|
211
|
+
searchable_fields = ['name', 'description']
|
|
212
|
+
|
|
213
|
+
@classmethod
|
|
214
|
+
def turbodrf(cls):
|
|
215
|
+
return {
|
|
216
|
+
'endpoint': 'products', # Custom endpoint
|
|
217
|
+
'fields': {
|
|
218
|
+
'list': ['name', 'category__name', 'price'],
|
|
219
|
+
'detail': [
|
|
220
|
+
'name', 'description', 'price',
|
|
221
|
+
'category__name', 'category__description'
|
|
222
|
+
]
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Settings
|
|
228
|
+
|
|
229
|
+
Add to your Django settings:
|
|
230
|
+
|
|
231
|
+
```python
|
|
232
|
+
# Required apps
|
|
233
|
+
INSTALLED_APPS = [
|
|
234
|
+
# ...
|
|
235
|
+
'rest_framework',
|
|
236
|
+
'django_filters',
|
|
237
|
+
'drf_yasg',
|
|
238
|
+
'turbodrf',
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
# Role-based permissions
|
|
242
|
+
TURBODRF_ROLES = {
|
|
243
|
+
'admin': [
|
|
244
|
+
# Model permissions
|
|
245
|
+
'app.model.read',
|
|
246
|
+
'app.model.create',
|
|
247
|
+
'app.model.update',
|
|
248
|
+
'app.model.delete',
|
|
249
|
+
# Field permissions
|
|
250
|
+
'app.model.field.read',
|
|
251
|
+
'app.model.field.write',
|
|
252
|
+
],
|
|
253
|
+
'editor': [
|
|
254
|
+
'app.model.read',
|
|
255
|
+
'app.model.update',
|
|
256
|
+
'app.model.field.read',
|
|
257
|
+
],
|
|
258
|
+
'viewer': [
|
|
259
|
+
'app.model.read',
|
|
260
|
+
]
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## API Endpoints
|
|
265
|
+
|
|
266
|
+
For each model, TurboDRF generates:
|
|
267
|
+
|
|
268
|
+
| Method | Endpoint | Description |
|
|
269
|
+
|--------|----------|-------------|
|
|
270
|
+
| GET | `/api/{model}s/` | List all objects |
|
|
271
|
+
| POST | `/api/{model}s/` | Create new object |
|
|
272
|
+
| GET | `/api/{model}s/{id}/` | Retrieve specific object |
|
|
273
|
+
| PUT | `/api/{model}s/{id}/` | Update object (full) |
|
|
274
|
+
| PATCH | `/api/{model}s/{id}/` | Update object (partial) |
|
|
275
|
+
| DELETE | `/api/{model}s/{id}/` | Delete object |
|
|
276
|
+
| OPTIONS | `/api/{model}s/` | Get metadata |
|
|
277
|
+
|
|
278
|
+
## Query Parameters
|
|
279
|
+
|
|
280
|
+
### Pagination
|
|
281
|
+
|
|
282
|
+
| Parameter | Type | Default | Description |
|
|
283
|
+
|-----------|------|---------|-------------|
|
|
284
|
+
| `page` | int | 1 | Page number |
|
|
285
|
+
| `page_size` | int | 20 | Items per page (max 100) |
|
|
286
|
+
|
|
287
|
+
**Example**: `/api/books/?page=2&page_size=50`
|
|
288
|
+
|
|
289
|
+
### Search
|
|
290
|
+
|
|
291
|
+
| Parameter | Type | Description |
|
|
292
|
+
|-----------|------|-------------|
|
|
293
|
+
| `search` | string | Search across `searchable_fields` |
|
|
294
|
+
|
|
295
|
+
**Example**: `/api/books/?search=django`
|
|
296
|
+
|
|
297
|
+
### Filtering
|
|
298
|
+
|
|
299
|
+
Use Django's field lookups:
|
|
300
|
+
|
|
301
|
+
```
|
|
302
|
+
/api/books/?price__gte=10&price__lte=50
|
|
303
|
+
/api/books/?author__name__icontains=smith
|
|
304
|
+
/api/books/?published_date__year=2023
|
|
305
|
+
/api/books/?is_active=true
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Ordering
|
|
309
|
+
|
|
310
|
+
| Parameter | Type | Description |
|
|
311
|
+
|-----------|------|-------------|
|
|
312
|
+
| `ordering` | string | Field(s) to order by |
|
|
313
|
+
|
|
314
|
+
**Examples**:
|
|
315
|
+
- `/api/books/?ordering=price` (ascending)
|
|
316
|
+
- `/api/books/?ordering=-price` (descending)
|
|
317
|
+
- `/api/books/?ordering=-price,title` (multiple fields)
|
|
318
|
+
|
|
319
|
+
## Response Formats
|
|
320
|
+
|
|
321
|
+
### List Response
|
|
322
|
+
|
|
323
|
+
```json
|
|
324
|
+
{
|
|
325
|
+
"pagination": {
|
|
326
|
+
"next": "http://example.com/api/books/?page=2",
|
|
327
|
+
"previous": null,
|
|
328
|
+
"current_page": 1,
|
|
329
|
+
"total_pages": 5,
|
|
330
|
+
"total_items": 100
|
|
331
|
+
},
|
|
332
|
+
"data": [
|
|
333
|
+
{
|
|
334
|
+
"id": 1,
|
|
335
|
+
"title": "Django for Beginners",
|
|
336
|
+
"author_name": "John Smith",
|
|
337
|
+
"price": "29.99"
|
|
338
|
+
}
|
|
339
|
+
// ... more items
|
|
340
|
+
]
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Detail Response
|
|
345
|
+
|
|
346
|
+
```json
|
|
347
|
+
{
|
|
348
|
+
"id": 1,
|
|
349
|
+
"title": "Django for Beginners",
|
|
350
|
+
"description": "Learn Django step by step",
|
|
351
|
+
"author_name": "John Smith",
|
|
352
|
+
"author_email": "john@example.com",
|
|
353
|
+
"price": "29.99",
|
|
354
|
+
"created_at": "2024-01-01T00:00:00Z"
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
### Error Response
|
|
359
|
+
|
|
360
|
+
```json
|
|
361
|
+
{
|
|
362
|
+
"detail": "Not found."
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
```json
|
|
367
|
+
{
|
|
368
|
+
"field_name": [
|
|
369
|
+
"This field is required."
|
|
370
|
+
]
|
|
371
|
+
}
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Error Handling
|
|
375
|
+
|
|
376
|
+
### HTTP Status Codes
|
|
377
|
+
|
|
378
|
+
| Code | Description | When Used |
|
|
379
|
+
|------|-------------|-----------|
|
|
380
|
+
| 200 | OK | Successful GET, PUT, PATCH |
|
|
381
|
+
| 201 | Created | Successful POST |
|
|
382
|
+
| 204 | No Content | Successful DELETE |
|
|
383
|
+
| 400 | Bad Request | Invalid data |
|
|
384
|
+
| 401 | Unauthorized | No authentication |
|
|
385
|
+
| 403 | Forbidden | No permission |
|
|
386
|
+
| 404 | Not Found | Object doesn't exist |
|
|
387
|
+
| 405 | Method Not Allowed | Invalid HTTP method |
|
|
388
|
+
| 500 | Server Error | Internal error |
|
|
389
|
+
|
|
390
|
+
### Common Errors
|
|
391
|
+
|
|
392
|
+
#### Permission Denied
|
|
393
|
+
|
|
394
|
+
```json
|
|
395
|
+
{
|
|
396
|
+
"detail": "You do not have permission to perform this action."
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Solution**: Check user roles and permissions in `TURBODRF_ROLES`.
|
|
401
|
+
|
|
402
|
+
#### Field Not Found
|
|
403
|
+
|
|
404
|
+
```json
|
|
405
|
+
{
|
|
406
|
+
"detail": "Field 'invalid_field' does not exist on model 'Book'."
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**Solution**: Check field names in model's `turbodrf()` configuration.
|
|
411
|
+
|
|
412
|
+
#### Invalid Filter
|
|
413
|
+
|
|
414
|
+
```json
|
|
415
|
+
{
|
|
416
|
+
"detail": "Invalid filter: 'invalid_lookup'."
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Solution**: Use valid Django field lookups.
|
|
421
|
+
|
|
422
|
+
## Advanced Usage
|
|
423
|
+
|
|
424
|
+
### Custom ViewSet Methods
|
|
425
|
+
|
|
426
|
+
```python
|
|
427
|
+
from turbodrf import TurboDRFViewSet
|
|
428
|
+
from rest_framework.decorators import action
|
|
429
|
+
from rest_framework.response import Response
|
|
430
|
+
|
|
431
|
+
class CustomBookViewSet(TurboDRFViewSet):
|
|
432
|
+
model = Book
|
|
433
|
+
|
|
434
|
+
@action(detail=True, methods=['post'])
|
|
435
|
+
def set_favorite(self, request, pk=None):
|
|
436
|
+
book = self.get_object()
|
|
437
|
+
# Custom logic
|
|
438
|
+
return Response({'status': 'favorite set'})
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Extending Serializers
|
|
442
|
+
|
|
443
|
+
```python
|
|
444
|
+
from turbodrf import TurboDRFSerializer
|
|
445
|
+
|
|
446
|
+
class CustomBookSerializer(TurboDRFSerializer):
|
|
447
|
+
# Add custom fields or methods
|
|
448
|
+
|
|
449
|
+
class Meta:
|
|
450
|
+
model = Book
|
|
451
|
+
fields = ['title', 'author', 'custom_field']
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Performance Optimization
|
|
455
|
+
|
|
456
|
+
TurboDRF automatically optimizes queries, but you can enhance it:
|
|
457
|
+
|
|
458
|
+
```python
|
|
459
|
+
class Book(models.Model, TurboDRFMixin):
|
|
460
|
+
# Model fields
|
|
461
|
+
|
|
462
|
+
@classmethod
|
|
463
|
+
def turbodrf(cls):
|
|
464
|
+
return {
|
|
465
|
+
'fields': {
|
|
466
|
+
'list': ['title', 'author__name'], # Minimal fields
|
|
467
|
+
'detail': '__all__' # All fields in detail
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
This reduces data transfer in list views while providing complete information in detail views.
|