django-nativemojo 0.1.15__py3-none-any.whl → 0.1.17__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.
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.17.dist-info}/METADATA +3 -2
- django_nativemojo-0.1.17.dist-info/RECORD +302 -0
- mojo/__init__.py +1 -1
- mojo/apps/account/management/commands/serializer_admin.py +121 -1
- mojo/apps/account/migrations/0006_add_device_tracking_models.py +72 -0
- mojo/apps/account/migrations/0007_delete_userdevicelocation.py +16 -0
- mojo/apps/account/migrations/0008_userdevicelocation.py +33 -0
- mojo/apps/account/migrations/0009_geolocatedip_subnet.py +18 -0
- mojo/apps/account/migrations/0010_group_avatar.py +20 -0
- mojo/apps/account/migrations/0011_user_org_registereddevice_pushconfig_and_more.py +118 -0
- mojo/apps/account/migrations/0012_remove_pushconfig_apns_key_file_and_more.py +21 -0
- mojo/apps/account/migrations/0013_pushconfig_test_mode_alter_pushconfig_apns_enabled_and_more.py +28 -0
- mojo/apps/account/migrations/0014_notificationdelivery_data_payload_and_more.py +48 -0
- mojo/apps/account/models/__init__.py +2 -0
- mojo/apps/account/models/device.py +279 -0
- mojo/apps/account/models/group.py +294 -8
- mojo/apps/account/models/member.py +14 -1
- mojo/apps/account/models/push/__init__.py +4 -0
- mojo/apps/account/models/push/config.py +112 -0
- mojo/apps/account/models/push/delivery.py +93 -0
- mojo/apps/account/models/push/device.py +66 -0
- mojo/apps/account/models/push/template.py +99 -0
- mojo/apps/account/models/user.py +190 -17
- mojo/apps/account/rest/__init__.py +2 -0
- mojo/apps/account/rest/device.py +39 -0
- mojo/apps/account/rest/group.py +8 -0
- mojo/apps/account/rest/push.py +187 -0
- mojo/apps/account/rest/user.py +95 -5
- mojo/apps/account/services/__init__.py +1 -0
- mojo/apps/account/services/push.py +363 -0
- mojo/apps/aws/migrations/0001_initial.py +206 -0
- mojo/apps/aws/migrations/0002_emaildomain_can_recv_emaildomain_can_send_and_more.py +28 -0
- mojo/apps/aws/migrations/0003_mailbox_is_domain_default_mailbox_is_system_default_and_more.py +31 -0
- mojo/apps/aws/migrations/0004_s3bucket.py +39 -0
- mojo/apps/aws/migrations/0005_alter_emaildomain_region_delete_s3bucket.py +21 -0
- mojo/apps/aws/models/__init__.py +19 -0
- mojo/apps/aws/models/email_attachment.py +99 -0
- mojo/apps/aws/models/email_domain.py +218 -0
- mojo/apps/aws/models/email_template.py +132 -0
- mojo/apps/aws/models/incoming_email.py +197 -0
- mojo/apps/aws/models/mailbox.py +288 -0
- mojo/apps/aws/models/sent_message.py +175 -0
- mojo/apps/aws/rest/__init__.py +6 -0
- mojo/apps/aws/rest/email.py +33 -0
- mojo/apps/aws/rest/email_ops.py +183 -0
- mojo/apps/aws/rest/messages.py +32 -0
- mojo/apps/aws/rest/send.py +101 -0
- mojo/apps/aws/rest/sns.py +403 -0
- mojo/apps/aws/rest/templates.py +19 -0
- mojo/apps/aws/services/__init__.py +32 -0
- mojo/apps/aws/services/email.py +390 -0
- mojo/apps/aws/services/email_ops.py +548 -0
- mojo/apps/docit/__init__.py +6 -0
- mojo/apps/docit/markdown_plugins/syntax_highlight.py +25 -0
- mojo/apps/docit/markdown_plugins/toc.py +12 -0
- mojo/apps/docit/migrations/0001_initial.py +113 -0
- mojo/apps/docit/migrations/0002_alter_book_modified_by_alter_page_modified_by.py +26 -0
- mojo/apps/docit/migrations/0003_alter_book_group.py +20 -0
- mojo/apps/docit/models/__init__.py +17 -0
- mojo/apps/docit/models/asset.py +231 -0
- mojo/apps/docit/models/book.py +227 -0
- mojo/apps/docit/models/page.py +319 -0
- mojo/apps/docit/models/page_revision.py +203 -0
- mojo/apps/docit/rest/__init__.py +10 -0
- mojo/apps/docit/rest/asset.py +17 -0
- mojo/apps/docit/rest/book.py +22 -0
- mojo/apps/docit/rest/page.py +22 -0
- mojo/apps/docit/rest/page_revision.py +17 -0
- mojo/apps/docit/services/__init__.py +11 -0
- mojo/apps/docit/services/docit.py +315 -0
- mojo/apps/docit/services/markdown.py +44 -0
- mojo/apps/fileman/backends/s3.py +209 -0
- mojo/apps/fileman/models/file.py +45 -9
- mojo/apps/fileman/models/manager.py +269 -3
- mojo/apps/incident/migrations/0007_event_uid.py +18 -0
- mojo/apps/incident/migrations/0008_ticket_ticketnote.py +55 -0
- mojo/apps/incident/migrations/0009_incident_status.py +18 -0
- mojo/apps/incident/migrations/0010_event_country_code.py +18 -0
- mojo/apps/incident/migrations/0011_incident_country_code.py +18 -0
- mojo/apps/incident/migrations/0012_alter_incident_status.py +18 -0
- mojo/apps/incident/models/__init__.py +1 -0
- mojo/apps/incident/models/event.py +35 -0
- mojo/apps/incident/models/incident.py +2 -0
- mojo/apps/incident/models/ticket.py +62 -0
- mojo/apps/incident/reporter.py +21 -3
- mojo/apps/incident/rest/__init__.py +1 -0
- mojo/apps/incident/rest/ticket.py +43 -0
- mojo/apps/jobs/__init__.py +489 -0
- mojo/apps/jobs/adapters.py +24 -0
- mojo/apps/jobs/cli.py +616 -0
- mojo/apps/jobs/daemon.py +370 -0
- mojo/apps/jobs/examples/sample_jobs.py +376 -0
- mojo/apps/jobs/examples/webhook_examples.py +203 -0
- mojo/apps/jobs/handlers/__init__.py +5 -0
- mojo/apps/jobs/handlers/webhook.py +317 -0
- mojo/apps/jobs/job_engine.py +734 -0
- mojo/apps/jobs/keys.py +203 -0
- mojo/apps/jobs/local_queue.py +363 -0
- mojo/apps/jobs/management/__init__.py +3 -0
- mojo/apps/jobs/management/commands/__init__.py +3 -0
- mojo/apps/jobs/manager.py +1327 -0
- mojo/apps/jobs/migrations/0001_initial.py +97 -0
- mojo/apps/jobs/migrations/0002_alter_job_max_retries_joblog.py +39 -0
- mojo/apps/jobs/models/__init__.py +6 -0
- mojo/apps/jobs/models/job.py +441 -0
- mojo/apps/jobs/rest/__init__.py +2 -0
- mojo/apps/jobs/rest/control.py +466 -0
- mojo/apps/jobs/rest/jobs.py +421 -0
- mojo/apps/jobs/scheduler.py +571 -0
- mojo/apps/jobs/services/__init__.py +6 -0
- mojo/apps/jobs/services/job_actions.py +465 -0
- mojo/apps/jobs/settings.py +209 -0
- mojo/apps/logit/models/log.py +3 -0
- mojo/apps/metrics/__init__.py +8 -1
- mojo/apps/metrics/redis_metrics.py +198 -0
- mojo/apps/metrics/rest/__init__.py +3 -0
- mojo/apps/metrics/rest/categories.py +266 -0
- mojo/apps/metrics/rest/helpers.py +48 -0
- mojo/apps/metrics/rest/permissions.py +99 -0
- mojo/apps/metrics/rest/values.py +277 -0
- mojo/apps/metrics/utils.py +17 -0
- mojo/decorators/http.py +40 -1
- mojo/helpers/aws/__init__.py +11 -7
- mojo/helpers/aws/inbound_email.py +309 -0
- mojo/helpers/aws/kms.py +413 -0
- mojo/helpers/aws/ses_domain.py +959 -0
- mojo/helpers/crypto/__init__.py +1 -1
- mojo/helpers/crypto/utils.py +15 -0
- mojo/helpers/location/__init__.py +2 -0
- mojo/helpers/location/countries.py +262 -0
- mojo/helpers/location/geolocation.py +196 -0
- mojo/helpers/logit.py +37 -0
- mojo/helpers/redis/__init__.py +2 -0
- mojo/helpers/redis/adapter.py +606 -0
- mojo/helpers/redis/client.py +48 -0
- mojo/helpers/redis/pool.py +225 -0
- mojo/helpers/request.py +8 -0
- mojo/helpers/response.py +8 -0
- mojo/middleware/auth.py +1 -1
- mojo/middleware/cors.py +40 -0
- mojo/middleware/logging.py +131 -12
- mojo/middleware/mojo.py +5 -0
- mojo/models/rest.py +271 -57
- mojo/models/secrets.py +86 -0
- mojo/serializers/__init__.py +16 -10
- mojo/serializers/core/__init__.py +90 -0
- mojo/serializers/core/cache/__init__.py +121 -0
- mojo/serializers/core/cache/backends.py +518 -0
- mojo/serializers/core/cache/base.py +102 -0
- mojo/serializers/core/cache/disabled.py +181 -0
- mojo/serializers/core/cache/memory.py +287 -0
- mojo/serializers/core/cache/redis.py +533 -0
- mojo/serializers/core/cache/utils.py +454 -0
- mojo/serializers/{manager.py → core/manager.py} +53 -4
- mojo/serializers/core/serializer.py +475 -0
- mojo/serializers/{advanced/formats → formats}/csv.py +116 -139
- mojo/serializers/suggested_improvements.md +388 -0
- testit/client.py +1 -1
- testit/helpers.py +14 -0
- testit/runner.py +23 -6
- django_nativemojo-0.1.15.dist-info/RECORD +0 -234
- mojo/apps/notify/README.md +0 -91
- mojo/apps/notify/README_NOTIFICATIONS.md +0 -566
- mojo/apps/notify/admin.py +0 -52
- mojo/apps/notify/handlers/example_handlers.py +0 -516
- mojo/apps/notify/handlers/ses/__init__.py +0 -25
- mojo/apps/notify/handlers/ses/complaint.py +0 -25
- mojo/apps/notify/handlers/ses/message.py +0 -86
- mojo/apps/notify/management/commands/__init__.py +0 -1
- mojo/apps/notify/management/commands/process_notifications.py +0 -370
- mojo/apps/notify/mod +0 -0
- mojo/apps/notify/models/__init__.py +0 -12
- mojo/apps/notify/models/account.py +0 -128
- mojo/apps/notify/models/attachment.py +0 -24
- mojo/apps/notify/models/bounce.py +0 -68
- mojo/apps/notify/models/complaint.py +0 -40
- mojo/apps/notify/models/inbox.py +0 -113
- mojo/apps/notify/models/inbox_message.py +0 -173
- mojo/apps/notify/models/outbox.py +0 -129
- mojo/apps/notify/models/outbox_message.py +0 -288
- mojo/apps/notify/models/template.py +0 -30
- mojo/apps/notify/providers/aws.py +0 -73
- mojo/apps/notify/rest/ses.py +0 -0
- mojo/apps/notify/utils/__init__.py +0 -2
- mojo/apps/notify/utils/notifications.py +0 -404
- mojo/apps/notify/utils/parsing.py +0 -202
- mojo/apps/notify/utils/render.py +0 -144
- mojo/apps/tasks/README.md +0 -118
- mojo/apps/tasks/__init__.py +0 -44
- mojo/apps/tasks/manager.py +0 -644
- mojo/apps/tasks/rest/__init__.py +0 -2
- mojo/apps/tasks/rest/hooks.py +0 -0
- mojo/apps/tasks/rest/tasks.py +0 -76
- mojo/apps/tasks/runner.py +0 -439
- mojo/apps/tasks/task.py +0 -99
- mojo/apps/tasks/tq_handlers.py +0 -132
- mojo/helpers/crypto/__pycache__/hash.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/sign.cpython-310.pyc +0 -0
- mojo/helpers/crypto/__pycache__/utils.cpython-310.pyc +0 -0
- mojo/helpers/redis.py +0 -10
- mojo/models/meta.py +0 -262
- mojo/serializers/advanced/README.md +0 -363
- mojo/serializers/advanced/__init__.py +0 -247
- mojo/serializers/advanced/formats/__init__.py +0 -28
- mojo/serializers/advanced/formats/excel.py +0 -516
- mojo/serializers/advanced/formats/json.py +0 -239
- mojo/serializers/advanced/formats/response.py +0 -485
- mojo/serializers/advanced/serializer.py +0 -568
- mojo/serializers/optimized.py +0 -618
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.17.dist-info}/LICENSE +0 -0
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.17.dist-info}/NOTICE +0 -0
- {django_nativemojo-0.1.15.dist-info → django_nativemojo-0.1.17.dist-info}/WHEEL +0 -0
- /mojo/apps/{notify → aws/migrations}/__init__.py +0 -0
- /mojo/apps/{notify/handlers → docit/markdown_plugins}/__init__.py +0 -0
- /mojo/apps/{notify/management → docit/migrations}/__init__.py +0 -0
- /mojo/apps/{notify/providers → jobs/examples}/__init__.py +0 -0
- /mojo/apps/{notify/rest → jobs/migrations}/__init__.py +0 -0
- /mojo/{serializers → rest}/openapi.py +0 -0
- /mojo/serializers/{settings_example.py → examples/settings.py} +0 -0
- /mojo/{apps/notify/handlers/ses/bounce.py → serializers/formats/__init__.py} +0 -0
- /mojo/serializers/{advanced/formats → formats}/localizers.py +0 -0
@@ -1,363 +0,0 @@
|
|
1
|
-
# Advanced Django Model Serializer
|
2
|
-
|
3
|
-
A comprehensive serialization library for Django models and QuerySets with support for multiple output formats, performance optimizations, and advanced configuration through `RestMeta.GRAPHS`.
|
4
|
-
|
5
|
-
## Features
|
6
|
-
|
7
|
-
- **RestMeta.GRAPHS Configuration**: Use declarative graph configurations for consistent serialization
|
8
|
-
- **Multiple Output Formats**: JSON, CSV, Excel, HTML debug views
|
9
|
-
- **Performance Optimizations**: Caching, select_related, streaming responses
|
10
|
-
- **Nested Relationships**: Deep serialization of related models
|
11
|
-
- **Custom Fields**: Support for methods, properties, and computed values
|
12
|
-
- **Pagination & Sorting**: Built-in collection handling with pagination
|
13
|
-
- **Localization**: Field-level formatting and localization
|
14
|
-
|
15
|
-
## Quick Start
|
16
|
-
|
17
|
-
### Basic Usage
|
18
|
-
|
19
|
-
```python
|
20
|
-
from mojo.serializers.advanced import AdvancedGraphSerializer, CollectionSerializer
|
21
|
-
|
22
|
-
# Serialize a single model instance
|
23
|
-
user = User.objects.get(pk=1)
|
24
|
-
serializer = AdvancedGraphSerializer(user, graph="detail")
|
25
|
-
data = serializer.serialize()
|
26
|
-
|
27
|
-
# Serialize a QuerySet
|
28
|
-
users = User.objects.all()
|
29
|
-
serializer = CollectionSerializer(users, graph="list", size=25)
|
30
|
-
response_data = serializer.serialize()
|
31
|
-
|
32
|
-
# Create HTTP response
|
33
|
-
response = serializer.to_response(request)
|
34
|
-
```
|
35
|
-
|
36
|
-
### RestMeta.GRAPHS Configuration
|
37
|
-
|
38
|
-
Define serialization graphs in your Django models:
|
39
|
-
|
40
|
-
```python
|
41
|
-
class User(models.Model):
|
42
|
-
name = models.CharField(max_length=100)
|
43
|
-
email = models.EmailField()
|
44
|
-
profile = models.OneToOneField('Profile', on_delete=models.CASCADE)
|
45
|
-
posts = models.ForeignKey('Post', related_name='author')
|
46
|
-
created = models.DateTimeField(auto_now_add=True)
|
47
|
-
|
48
|
-
class RestMeta:
|
49
|
-
GRAPHS = {
|
50
|
-
"default": {
|
51
|
-
"fields": ["id", "name", "email", "created"],
|
52
|
-
},
|
53
|
-
"list": {
|
54
|
-
"fields": ["id", "name", "email"],
|
55
|
-
"extra": [
|
56
|
-
("get_full_name", "full_name"), # Method with alias
|
57
|
-
"post_count", # Property or method
|
58
|
-
]
|
59
|
-
},
|
60
|
-
"detail": {
|
61
|
-
"fields": ["id", "name", "email", "created"],
|
62
|
-
"extra": ["get_full_name", "is_active"],
|
63
|
-
"graphs": {
|
64
|
-
"profile": "summary", # Related object with sub-graph
|
65
|
-
"posts": "list", # Related QuerySet
|
66
|
-
}
|
67
|
-
},
|
68
|
-
"export": {
|
69
|
-
"fields": ["id", "name", "email", "created"],
|
70
|
-
"extra": [("profile.bio", "biography")], # Nested field access
|
71
|
-
}
|
72
|
-
}
|
73
|
-
|
74
|
-
def get_full_name(self):
|
75
|
-
return f"{self.first_name} {self.last_name}"
|
76
|
-
|
77
|
-
@property
|
78
|
-
def post_count(self):
|
79
|
-
return self.posts.count()
|
80
|
-
|
81
|
-
class Profile(models.Model):
|
82
|
-
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
83
|
-
bio = models.TextField()
|
84
|
-
avatar = models.ImageField()
|
85
|
-
|
86
|
-
class RestMeta:
|
87
|
-
GRAPHS = {
|
88
|
-
"summary": {
|
89
|
-
"fields": ["bio"],
|
90
|
-
"extra": ["avatar_url"]
|
91
|
-
}
|
92
|
-
}
|
93
|
-
|
94
|
-
def avatar_url(self):
|
95
|
-
return self.avatar.url if self.avatar else None
|
96
|
-
```
|
97
|
-
|
98
|
-
## Advanced Usage
|
99
|
-
|
100
|
-
### Multiple Output Formats
|
101
|
-
|
102
|
-
```python
|
103
|
-
from mojo.serializers.advanced import (
|
104
|
-
serialize, to_response, to_csv_response, to_excel_response
|
105
|
-
)
|
106
|
-
|
107
|
-
# Auto-detect format from request
|
108
|
-
def user_list_view(request):
|
109
|
-
users = User.objects.all()
|
110
|
-
return to_response(users, graph="list", request=request)
|
111
|
-
|
112
|
-
# Force specific formats
|
113
|
-
def user_csv_export(request):
|
114
|
-
users = User.objects.all()
|
115
|
-
return to_csv_response(
|
116
|
-
users,
|
117
|
-
fields=["name", "email", "created"],
|
118
|
-
filename="users.csv",
|
119
|
-
request=request
|
120
|
-
)
|
121
|
-
|
122
|
-
def user_excel_export(request):
|
123
|
-
users = User.objects.all()
|
124
|
-
return to_excel_response(
|
125
|
-
users,
|
126
|
-
graph="export",
|
127
|
-
filename="users.xlsx",
|
128
|
-
request=request
|
129
|
-
)
|
130
|
-
```
|
131
|
-
|
132
|
-
### Performance Optimizations
|
133
|
-
|
134
|
-
```python
|
135
|
-
# Automatic select_related for foreign keys
|
136
|
-
users = User.objects.all() # Will auto-add select_related('profile')
|
137
|
-
serializer = AdvancedGraphSerializer(users, graph="detail", many=True)
|
138
|
-
|
139
|
-
# Caching for repeated serialization
|
140
|
-
cache = {}
|
141
|
-
for user in users:
|
142
|
-
data = AdvancedGraphSerializer(user, graph="detail", cache=cache).serialize()
|
143
|
-
|
144
|
-
# Streaming responses for large datasets
|
145
|
-
def large_export(request):
|
146
|
-
large_queryset = User.objects.all() # 100k+ records
|
147
|
-
return to_csv_response(
|
148
|
-
large_queryset,
|
149
|
-
fields=["name", "email"],
|
150
|
-
filename="all_users.csv",
|
151
|
-
stream=True # Enables streaming
|
152
|
-
)
|
153
|
-
```
|
154
|
-
|
155
|
-
### Collection Serialization with Pagination
|
156
|
-
|
157
|
-
```python
|
158
|
-
from mojo.serializers.advanced import CollectionSerializer
|
159
|
-
|
160
|
-
def paginated_users(request):
|
161
|
-
users = User.objects.all()
|
162
|
-
|
163
|
-
serializer = CollectionSerializer(
|
164
|
-
users,
|
165
|
-
graph="list",
|
166
|
-
size=request.GET.get('size', 25),
|
167
|
-
start=request.GET.get('start', 0),
|
168
|
-
sort=request.GET.get('sort', 'name'),
|
169
|
-
request=request
|
170
|
-
)
|
171
|
-
|
172
|
-
return serializer.to_response()
|
173
|
-
|
174
|
-
# Response format:
|
175
|
-
{
|
176
|
-
"data": [...],
|
177
|
-
"status": true,
|
178
|
-
"count": 1500,
|
179
|
-
"size": 25,
|
180
|
-
"start": 0,
|
181
|
-
"sort": ["name"],
|
182
|
-
"graph": "list",
|
183
|
-
"datetime": 1640995200
|
184
|
-
}
|
185
|
-
```
|
186
|
-
|
187
|
-
### Custom Localization
|
188
|
-
|
189
|
-
```python
|
190
|
-
from mojo.serializers.advanced.formats.localizers import register_localizer
|
191
|
-
|
192
|
-
# Register custom localizer
|
193
|
-
@register_localizer('currency_eur')
|
194
|
-
def format_euro(value, extra=None):
|
195
|
-
return f"€{value:.2f}"
|
196
|
-
|
197
|
-
# Use in CSV/Excel export
|
198
|
-
csv_response = to_csv_response(
|
199
|
-
Product.objects.all(),
|
200
|
-
fields=['name', 'price'],
|
201
|
-
localize={'price': 'currency_eur'},
|
202
|
-
filename='products.csv'
|
203
|
-
)
|
204
|
-
```
|
205
|
-
|
206
|
-
### Response Helpers
|
207
|
-
|
208
|
-
```python
|
209
|
-
from mojo.serializers.advanced import (
|
210
|
-
rest_success, rest_error, rest_not_found, rest_permission_denied
|
211
|
-
)
|
212
|
-
|
213
|
-
def api_view(request):
|
214
|
-
try:
|
215
|
-
user = User.objects.get(pk=request.GET['id'])
|
216
|
-
data = serialize(user, graph="detail")
|
217
|
-
return rest_success(request, data)
|
218
|
-
except User.DoesNotExist:
|
219
|
-
return rest_not_found(request, "User not found")
|
220
|
-
except PermissionError:
|
221
|
-
return rest_permission_denied(request, "Access denied")
|
222
|
-
except Exception as e:
|
223
|
-
return rest_error(request, str(e))
|
224
|
-
```
|
225
|
-
|
226
|
-
## Configuration Options
|
227
|
-
|
228
|
-
### Serializer Options
|
229
|
-
|
230
|
-
```python
|
231
|
-
serializer = AdvancedGraphSerializer(
|
232
|
-
instance=user,
|
233
|
-
graph="detail", # Graph configuration to use
|
234
|
-
many=False, # Whether serializing multiple objects
|
235
|
-
request=request, # Django request for context
|
236
|
-
cache={}, # Shared cache for performance
|
237
|
-
format="json" # Output format hint
|
238
|
-
)
|
239
|
-
```
|
240
|
-
|
241
|
-
### Collection Options
|
242
|
-
|
243
|
-
```python
|
244
|
-
serializer = CollectionSerializer(
|
245
|
-
queryset=users,
|
246
|
-
graph="list", # Graph configuration
|
247
|
-
size=25, # Page size
|
248
|
-
start=0, # Start offset
|
249
|
-
sort="name,-created", # Sort fields (- for descending)
|
250
|
-
format="json", # Output format
|
251
|
-
request=request # Django request
|
252
|
-
)
|
253
|
-
```
|
254
|
-
|
255
|
-
### Export Options
|
256
|
-
|
257
|
-
```python
|
258
|
-
# CSV Export
|
259
|
-
csv_response = to_csv_response(
|
260
|
-
queryset,
|
261
|
-
fields=['name', 'email'], # Fields to include
|
262
|
-
filename='export.csv', # Download filename
|
263
|
-
headers=['Name', 'Email'], # Custom column headers
|
264
|
-
localize={'date': 'date|%Y-%m-%d'}, # Field localization
|
265
|
-
stream=True # Enable streaming for large datasets
|
266
|
-
)
|
267
|
-
|
268
|
-
# Excel Export
|
269
|
-
excel_response = to_excel_response(
|
270
|
-
queryset,
|
271
|
-
fields=['name', 'email', 'created'],
|
272
|
-
filename='export.xlsx',
|
273
|
-
sheet_name='Users',
|
274
|
-
freeze_panes=True, # Freeze header row
|
275
|
-
auto_width=True # Auto-adjust column widths
|
276
|
-
)
|
277
|
-
```
|
278
|
-
|
279
|
-
## Graph Configuration Reference
|
280
|
-
|
281
|
-
### Field Types
|
282
|
-
|
283
|
-
```python
|
284
|
-
class RestMeta:
|
285
|
-
GRAPHS = {
|
286
|
-
"example": {
|
287
|
-
# Basic model fields
|
288
|
-
"fields": ["id", "name", "email"],
|
289
|
-
|
290
|
-
# Extra fields (methods, properties, computed values)
|
291
|
-
"extra": [
|
292
|
-
"method_name", # Simple method/property
|
293
|
-
("method_name", "alias"), # Method with alias
|
294
|
-
("nested.field", "flat_name"), # Nested field access
|
295
|
-
],
|
296
|
-
|
297
|
-
# Related object graphs
|
298
|
-
"graphs": {
|
299
|
-
"foreign_key_field": "sub_graph_name",
|
300
|
-
"many_to_many_field": "list_graph",
|
301
|
-
"reverse_fk": "related_graph"
|
302
|
-
}
|
303
|
-
}
|
304
|
-
}
|
305
|
-
```
|
306
|
-
|
307
|
-
### Nested Field Access
|
308
|
-
|
309
|
-
```python
|
310
|
-
# Access nested fields with dot notation
|
311
|
-
"extra": [
|
312
|
-
("user.profile.bio", "biography"),
|
313
|
-
("metadata.category.name", "category"),
|
314
|
-
("settings.preferences.theme", "theme")
|
315
|
-
]
|
316
|
-
```
|
317
|
-
|
318
|
-
## Performance Tips
|
319
|
-
|
320
|
-
1. **Use select_related**: The serializer automatically applies `select_related()` for foreign keys in your graph
|
321
|
-
2. **Enable caching**: Pass a shared cache dictionary when serializing multiple related objects
|
322
|
-
3. **Stream large exports**: Set `stream=True` for CSV exports with >1000 records
|
323
|
-
4. **Optimize graphs**: Keep graph configurations focused - avoid over-fetching data
|
324
|
-
5. **Use pagination**: Always paginate large QuerySets with CollectionSerializer
|
325
|
-
|
326
|
-
## API Reference
|
327
|
-
|
328
|
-
### Core Classes
|
329
|
-
|
330
|
-
- `AdvancedGraphSerializer`: Main serializer for single instances or lists
|
331
|
-
- `CollectionSerializer`: Specialized serializer for QuerySets with pagination
|
332
|
-
- `ResponseFormatter`: HTTP response handler for multiple formats
|
333
|
-
|
334
|
-
### Format Handlers
|
335
|
-
|
336
|
-
- `JsonFormatter`: Enhanced JSON serialization with ujson support
|
337
|
-
- `CsvFormatter`: CSV export with streaming support
|
338
|
-
- `ExcelFormatter`: Excel export with openpyxl
|
339
|
-
- `ResponseFormatter`: Multi-format HTTP response handler
|
340
|
-
|
341
|
-
### Convenience Functions
|
342
|
-
|
343
|
-
- `serialize()`: Universal serialization function
|
344
|
-
- `to_response()`: Quick HTTP response generation
|
345
|
-
- `to_csv_response()`: CSV export response
|
346
|
-
- `to_excel_response()`: Excel export response
|
347
|
-
|
348
|
-
### Response Helpers
|
349
|
-
|
350
|
-
- `rest_success()`, `rest_error()`: Status responses
|
351
|
-
- `rest_not_found()`, `rest_permission_denied()`: Error responses
|
352
|
-
- `get_cached_count()`: Cached QuerySet counting
|
353
|
-
|
354
|
-
## Requirements
|
355
|
-
|
356
|
-
- Django 3.2+
|
357
|
-
- Python 3.8+
|
358
|
-
- ujson (optional, for better JSON performance)
|
359
|
-
- openpyxl (optional, for Excel export)
|
360
|
-
|
361
|
-
## License
|
362
|
-
|
363
|
-
This project is part of the Django Mojo framework.
|
@@ -1,247 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Advanced Django Model and QuerySet Serializer
|
3
|
-
|
4
|
-
This module provides comprehensive serialization capabilities for Django models and QuerySets
|
5
|
-
with support for:
|
6
|
-
|
7
|
-
- RestMeta.GRAPHS configuration
|
8
|
-
- Multiple output formats (JSON, CSV, Excel, HTML)
|
9
|
-
- Nested relationships and custom fields
|
10
|
-
- Performance optimizations with caching and select_related
|
11
|
-
- Pagination and sorting for collections
|
12
|
-
- Streaming responses for large datasets
|
13
|
-
- Localization and field formatting
|
14
|
-
|
15
|
-
Main Classes:
|
16
|
-
AdvancedGraphSerializer: Serialize single model instances or lists
|
17
|
-
CollectionSerializer: Serialize QuerySets with pagination and sorting
|
18
|
-
ResponseFormatter: Handle HTTP responses in multiple formats
|
19
|
-
|
20
|
-
Usage Examples:
|
21
|
-
# Serialize a single model instance
|
22
|
-
serializer = AdvancedGraphSerializer(user, graph="detail")
|
23
|
-
data = serializer.serialize()
|
24
|
-
|
25
|
-
# Serialize a QuerySet
|
26
|
-
serializer = CollectionSerializer(User.objects.all(), graph="list")
|
27
|
-
response = serializer.to_response(request)
|
28
|
-
|
29
|
-
# Export to CSV
|
30
|
-
csv_response = rest_csv(request, User.objects.all(), fields=['name', 'email'])
|
31
|
-
"""
|
32
|
-
|
33
|
-
from .serializer import (
|
34
|
-
AdvancedGraphSerializer,
|
35
|
-
CollectionSerializer,
|
36
|
-
serialize_model,
|
37
|
-
serialize_collection,
|
38
|
-
serialize_to_response,
|
39
|
-
timeit
|
40
|
-
)
|
41
|
-
|
42
|
-
from .formats import (
|
43
|
-
JsonFormatter,
|
44
|
-
CsvFormatter,
|
45
|
-
ExcelFormatter,
|
46
|
-
ResponseFormatter,
|
47
|
-
get_formatter
|
48
|
-
)
|
49
|
-
|
50
|
-
from .formats.json import (
|
51
|
-
to_json,
|
52
|
-
to_pretty_json,
|
53
|
-
to_compact_json,
|
54
|
-
ExtendedJSONEncoder
|
55
|
-
)
|
56
|
-
|
57
|
-
from .formats.csv import (
|
58
|
-
generate_csv,
|
59
|
-
generate_csv_stream,
|
60
|
-
serialize_to_csv
|
61
|
-
)
|
62
|
-
|
63
|
-
from .formats.excel import (
|
64
|
-
generate_excel,
|
65
|
-
serialize_to_excel,
|
66
|
-
create_multi_sheet_excel,
|
67
|
-
qsetToExcel # Legacy compatibility
|
68
|
-
)
|
69
|
-
|
70
|
-
from .formats.response import (
|
71
|
-
rest_status,
|
72
|
-
rest_success,
|
73
|
-
rest_error,
|
74
|
-
rest_permission_denied,
|
75
|
-
rest_not_found,
|
76
|
-
rest_json,
|
77
|
-
rest_csv,
|
78
|
-
rest_excel,
|
79
|
-
rest_html,
|
80
|
-
get_cached_count,
|
81
|
-
get_request_elapsed,
|
82
|
-
)
|
83
|
-
|
84
|
-
from .formats.localizers import (
|
85
|
-
register_localizer,
|
86
|
-
get_localizer,
|
87
|
-
list_localizers,
|
88
|
-
apply_localizer,
|
89
|
-
localizer # decorator
|
90
|
-
)
|
91
|
-
|
92
|
-
# Version info
|
93
|
-
__version__ = "2.0.0"
|
94
|
-
__author__ = "Django Mojo Team"
|
95
|
-
|
96
|
-
# Public API
|
97
|
-
__all__ = [
|
98
|
-
# Main serializer classes
|
99
|
-
'AdvancedGraphSerializer',
|
100
|
-
'CollectionSerializer',
|
101
|
-
|
102
|
-
# Format handlers
|
103
|
-
'JsonFormatter',
|
104
|
-
'CsvFormatter',
|
105
|
-
'ExcelFormatter',
|
106
|
-
'ResponseFormatter',
|
107
|
-
|
108
|
-
# Convenience functions
|
109
|
-
'serialize_model',
|
110
|
-
'serialize_collection',
|
111
|
-
'serialize_to_response',
|
112
|
-
'serialize_to_csv',
|
113
|
-
'serialize_to_excel',
|
114
|
-
|
115
|
-
# JSON utilities
|
116
|
-
'to_json',
|
117
|
-
'to_pretty_json',
|
118
|
-
'to_compact_json',
|
119
|
-
'ExtendedJSONEncoder',
|
120
|
-
|
121
|
-
# Export functions
|
122
|
-
'generate_csv',
|
123
|
-
'generate_csv_stream',
|
124
|
-
'generate_excel',
|
125
|
-
'create_multi_sheet_excel',
|
126
|
-
|
127
|
-
# Response helpers
|
128
|
-
'rest_status',
|
129
|
-
'rest_success',
|
130
|
-
'rest_error',
|
131
|
-
'rest_permission_denied',
|
132
|
-
'rest_not_found',
|
133
|
-
'rest_json',
|
134
|
-
'rest_csv',
|
135
|
-
'rest_excel',
|
136
|
-
'rest_html',
|
137
|
-
|
138
|
-
# Utilities
|
139
|
-
'get_cached_count',
|
140
|
-
'get_request_elapsed',
|
141
|
-
'get_formatter',
|
142
|
-
'timeit',
|
143
|
-
|
144
|
-
# Localizers
|
145
|
-
'register_localizer',
|
146
|
-
'get_localizer',
|
147
|
-
'list_localizers',
|
148
|
-
'apply_localizer',
|
149
|
-
'localizer',
|
150
|
-
]
|
151
|
-
|
152
|
-
|
153
|
-
# Convenience shortcuts for common use cases
|
154
|
-
def serialize(instance, graph="default", many=None, request=None, format="json", **kwargs):
|
155
|
-
"""
|
156
|
-
Universal serialization function that automatically chooses the right serializer.
|
157
|
-
|
158
|
-
:param instance: Model instance, QuerySet, or list of objects
|
159
|
-
:param graph: RestMeta graph name to use
|
160
|
-
:param many: Force many=True for lists (auto-detected for QuerySets)
|
161
|
-
:param request: Django request object
|
162
|
-
:param format: Output format ('json', 'csv', 'excel', 'response')
|
163
|
-
:param kwargs: Additional options
|
164
|
-
:return: Serialized data or HttpResponse (if format='response')
|
165
|
-
"""
|
166
|
-
from django.db.models import QuerySet
|
167
|
-
|
168
|
-
# Auto-detect if we're dealing with a collection
|
169
|
-
if isinstance(instance, QuerySet):
|
170
|
-
if format == "response":
|
171
|
-
return CollectionSerializer(instance, graph=graph, request=request, **kwargs).to_response()
|
172
|
-
elif format in ["csv", "excel"]:
|
173
|
-
formatter = ResponseFormatter(request)
|
174
|
-
return formatter.format_response(instance, format, **kwargs)
|
175
|
-
else:
|
176
|
-
return CollectionSerializer(instance, graph=graph, request=request, **kwargs).serialize()
|
177
|
-
|
178
|
-
elif isinstance(instance, (list, tuple)) or many:
|
179
|
-
if format == "response":
|
180
|
-
return AdvancedGraphSerializer(instance, graph=graph, many=True, request=request, **kwargs).to_response()
|
181
|
-
elif format in ["csv", "excel"]:
|
182
|
-
formatter = ResponseFormatter(request)
|
183
|
-
return formatter.format_response(instance, format, **kwargs)
|
184
|
-
else:
|
185
|
-
return AdvancedGraphSerializer(instance, graph=graph, many=True, request=request, **kwargs).serialize()
|
186
|
-
|
187
|
-
else:
|
188
|
-
# Single instance
|
189
|
-
if format == "response":
|
190
|
-
return AdvancedGraphSerializer(instance, graph=graph, request=request, **kwargs).to_response()
|
191
|
-
elif format in ["csv", "excel"]:
|
192
|
-
formatter = ResponseFormatter(request)
|
193
|
-
return formatter.format_response([instance], format, **kwargs)
|
194
|
-
else:
|
195
|
-
return AdvancedGraphSerializer(instance, graph=graph, request=request, **kwargs).serialize()
|
196
|
-
|
197
|
-
|
198
|
-
def to_response(instance, graph="default", request=None, **kwargs):
|
199
|
-
"""
|
200
|
-
Shortcut to serialize and return HTTP response.
|
201
|
-
|
202
|
-
:param instance: Model instance, QuerySet, or list
|
203
|
-
:param graph: RestMeta graph name
|
204
|
-
:param request: Django request object
|
205
|
-
:param kwargs: Additional options
|
206
|
-
:return: HttpResponse
|
207
|
-
"""
|
208
|
-
return serialize(instance, graph=graph, request=request, format="response", **kwargs)
|
209
|
-
|
210
|
-
|
211
|
-
def to_csv_response(instance, fields=None, filename="export.csv", request=None, **kwargs):
|
212
|
-
"""
|
213
|
-
Shortcut to export data as CSV response.
|
214
|
-
|
215
|
-
:param instance: QuerySet or list of objects
|
216
|
-
:param fields: Fields to include in CSV
|
217
|
-
:param filename: Download filename
|
218
|
-
:param request: Django request object
|
219
|
-
:param kwargs: Additional options
|
220
|
-
:return: HttpResponse with CSV file
|
221
|
-
"""
|
222
|
-
formatter = ResponseFormatter(request)
|
223
|
-
return formatter.format_response(instance, "csv", fields=fields, filename=filename, **kwargs)
|
224
|
-
|
225
|
-
|
226
|
-
def to_excel_response(instance, fields=None, filename="export.xlsx", request=None, **kwargs):
|
227
|
-
"""
|
228
|
-
Shortcut to export data as Excel response.
|
229
|
-
|
230
|
-
:param instance: QuerySet or list of objects
|
231
|
-
:param fields: Fields to include in Excel
|
232
|
-
:param filename: Download filename
|
233
|
-
:param request: Django request object
|
234
|
-
:param kwargs: Additional options
|
235
|
-
:return: HttpResponse with Excel file
|
236
|
-
"""
|
237
|
-
formatter = ResponseFormatter(request)
|
238
|
-
return formatter.format_response(instance, "excel", fields=fields, filename=filename, **kwargs)
|
239
|
-
|
240
|
-
|
241
|
-
# Add shortcuts to __all__
|
242
|
-
__all__.extend([
|
243
|
-
'serialize',
|
244
|
-
'to_response',
|
245
|
-
'to_csv_response',
|
246
|
-
'to_excel_response'
|
247
|
-
])
|
@@ -1,28 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
Format handlers for advanced serialization.
|
3
|
-
Supports JSON, CSV, Excel, and other output formats.
|
4
|
-
"""
|
5
|
-
|
6
|
-
from .json import JsonFormatter
|
7
|
-
from .csv import CsvFormatter
|
8
|
-
from .excel import ExcelFormatter
|
9
|
-
from .response import ResponseFormatter
|
10
|
-
|
11
|
-
__all__ = [
|
12
|
-
'JsonFormatter',
|
13
|
-
'CsvFormatter',
|
14
|
-
'ExcelFormatter',
|
15
|
-
'ResponseFormatter'
|
16
|
-
]
|
17
|
-
|
18
|
-
# Default formatters
|
19
|
-
DEFAULT_FORMATTERS = {
|
20
|
-
'json': JsonFormatter,
|
21
|
-
'csv': CsvFormatter,
|
22
|
-
'excel': ExcelFormatter,
|
23
|
-
'xlsx': ExcelFormatter,
|
24
|
-
}
|
25
|
-
|
26
|
-
def get_formatter(format_type):
|
27
|
-
"""Get formatter class for the specified format type."""
|
28
|
-
return DEFAULT_FORMATTERS.get(format_type.lower())
|