drf-react-by-schema 0.26.0__tar.gz → 0.26.2__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.
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/PKG-INFO +1 -1
- drf_react_by_schema-0.26.2/drf_react_by_schema/management/commands/__init__.py +0 -0
- drf_react_by_schema-0.26.2/drf_react_by_schema/management/commands/sync_react.py +318 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/metadata.py +8 -3
- drf_react_by_schema-0.26.2/drf_react_by_schema/migrations/__init__.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/serializers.py +4 -2
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema.egg-info/PKG-INFO +1 -1
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema.egg-info/SOURCES.txt +3 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/setup.cfg +1 -1
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/LICENSE +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/MANIFEST.in +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/README.rst +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/__init__.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/admin.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/apps.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/autocomplete_serializers.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/autocomplete_viewsets.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/__init__.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/array.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/boolean.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/date.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/file.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/number.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/relational.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/serializers.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/text.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/filters.py +0 -0
- {drf_react_by_schema-0.26.0/drf_react_by_schema/migrations → drf_react_by_schema-0.26.2/drf_react_by_schema/management}/__init__.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/mixins.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/models.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/pagination.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/patches/__init__.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/patches/drf_serializers.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/renderers.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/tests.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/typescript_generator.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/urls.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/utils.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/utils_cache.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/viewsets.py +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema.egg-info/dependency_links.txt +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema.egg-info/requires.txt +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema.egg-info/top_level.txt +0 -0
- {drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/setup.py +0 -0
|
File without changes
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
import shutil
|
|
4
|
+
import importlib
|
|
5
|
+
import traceback
|
|
6
|
+
from django.conf import settings
|
|
7
|
+
from django.core.management.base import BaseCommand
|
|
8
|
+
from django.core.serializers.json import DjangoJSONEncoder
|
|
9
|
+
from django.utils.encoding import force_str
|
|
10
|
+
from django.apps import apps
|
|
11
|
+
from rest_framework.test import APIRequestFactory
|
|
12
|
+
from rest_framework.request import Request
|
|
13
|
+
|
|
14
|
+
from drf_react_by_schema import settings as package_settings
|
|
15
|
+
from drf_react_by_schema.metadata import Metadata
|
|
16
|
+
from drf_react_by_schema.typescript_generator import TypeScriptGenerator
|
|
17
|
+
from drf_react_by_schema import viewsets as drf_viewsets
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Command(BaseCommand):
|
|
21
|
+
help = "Syncs Django models to React schemas and types"
|
|
22
|
+
|
|
23
|
+
def handle(self, *args, **kwargs):
|
|
24
|
+
drf_settings = getattr(settings, "DRF_REACT_BY_SCHEMA", {})
|
|
25
|
+
base_dir = os.path.join(
|
|
26
|
+
settings.BASE_DIR,
|
|
27
|
+
drf_settings.get(
|
|
28
|
+
"REACT_APP_DIR",
|
|
29
|
+
"frontend",
|
|
30
|
+
),
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
output_dir = os.path.join(base_dir, "src/drfReactBySchema")
|
|
34
|
+
schema_path = os.path.join(output_dir, "schemas")
|
|
35
|
+
|
|
36
|
+
if os.path.exists(output_dir):
|
|
37
|
+
self.stdout.write(f"Cleaning output directory: {output_dir}")
|
|
38
|
+
shutil.rmtree(output_dir)
|
|
39
|
+
|
|
40
|
+
os.makedirs(schema_path, exist_ok=True)
|
|
41
|
+
|
|
42
|
+
apps_to_sync = drf_settings.get("APPS", [])
|
|
43
|
+
|
|
44
|
+
self.stdout.write(f"Syncing apps: {apps_to_sync}")
|
|
45
|
+
|
|
46
|
+
index_exports = ["import { SchemaLoader } from 'drf-react-by-schema';"]
|
|
47
|
+
|
|
48
|
+
factory = APIRequestFactory()
|
|
49
|
+
wsgi_request = factory.options("/")
|
|
50
|
+
request = Request(wsgi_request)
|
|
51
|
+
|
|
52
|
+
modules_to_sync = []
|
|
53
|
+
for app_label in apps_to_sync:
|
|
54
|
+
modules_to_sync.append(f"{app_label}.viewsets")
|
|
55
|
+
modules_to_sync.append("drf_react_by_schema.viewsets")
|
|
56
|
+
|
|
57
|
+
processed_models = set()
|
|
58
|
+
global_ts_gen = TypeScriptGenerator()
|
|
59
|
+
all_interfaces = []
|
|
60
|
+
|
|
61
|
+
for module_str in modules_to_sync:
|
|
62
|
+
try:
|
|
63
|
+
module = importlib.import_module(module_str)
|
|
64
|
+
module_name = module_str.split(".")[0]
|
|
65
|
+
self.stdout.write(f"Processing module: {module_name}...")
|
|
66
|
+
for viewset_name, viewset in module.__dict__.items():
|
|
67
|
+
if isinstance(viewset, type) and viewset_name not in [
|
|
68
|
+
"DRFReactBySchemaBaseModelViewSet",
|
|
69
|
+
"GenericRelatedModelViewSet",
|
|
70
|
+
"GenericAutocompleteViewSet",
|
|
71
|
+
"GenericViewSet",
|
|
72
|
+
"LoggingMixin",
|
|
73
|
+
"generated_nested_class",
|
|
74
|
+
"generated_class",
|
|
75
|
+
]:
|
|
76
|
+
for parent in viewset.mro():
|
|
77
|
+
if "ViewSet" in parent.__name__:
|
|
78
|
+
# Subclass to override properties that might be read-only on the base
|
|
79
|
+
class MockViewSet(viewset):
|
|
80
|
+
@property
|
|
81
|
+
def allowed_methods(self):
|
|
82
|
+
return [
|
|
83
|
+
"GET",
|
|
84
|
+
"POST",
|
|
85
|
+
"PUT",
|
|
86
|
+
"PATCH",
|
|
87
|
+
"DELETE",
|
|
88
|
+
"OPTIONS",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
def get_object(self):
|
|
92
|
+
# Avoid DB hit for metadata generation
|
|
93
|
+
if hasattr(self, "model") and self.model:
|
|
94
|
+
return self.model()
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
view_instance = MockViewSet()
|
|
98
|
+
view_instance.request = request
|
|
99
|
+
view_instance.format_kwarg = None
|
|
100
|
+
view_instance.kwargs = {"pk": 1}
|
|
101
|
+
view_instance.action = "create" # Ensure get_serializer implementation has a context
|
|
102
|
+
|
|
103
|
+
# Mock permissions
|
|
104
|
+
view_instance.check_permissions = lambda req: None
|
|
105
|
+
view_instance.check_object_permissions = (
|
|
106
|
+
lambda req, obj: None
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
# Check if it is a valid viewset to process
|
|
110
|
+
if (
|
|
111
|
+
not getattr(view_instance, "model", None)
|
|
112
|
+
and not getattr(view_instance, "queryset", None)
|
|
113
|
+
and viewset_name != "EndpointsViewSet"
|
|
114
|
+
):
|
|
115
|
+
continue
|
|
116
|
+
|
|
117
|
+
model_name = viewset_name.removesuffix("ViewSet")
|
|
118
|
+
if model_name in processed_models:
|
|
119
|
+
continue
|
|
120
|
+
processed_models.add(model_name)
|
|
121
|
+
|
|
122
|
+
# A. Generate Schema
|
|
123
|
+
meta_tool = Metadata()
|
|
124
|
+
raw_metadata = meta_tool.determine_metadata(
|
|
125
|
+
request, view_instance
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
simplified_schema = {
|
|
129
|
+
"schema": raw_metadata.get("actions", {}).get(
|
|
130
|
+
"POST", {}
|
|
131
|
+
),
|
|
132
|
+
"verbose_name": raw_metadata.get(
|
|
133
|
+
"verbose_name", ""
|
|
134
|
+
),
|
|
135
|
+
"verbose_name_plural": raw_metadata.get(
|
|
136
|
+
"verbose_name_plural", ""
|
|
137
|
+
),
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
# We want to export it as json
|
|
141
|
+
schema_var_name = f"{model_name}Schema"
|
|
142
|
+
json_filename = f"{schema_var_name}.json"
|
|
143
|
+
with open(
|
|
144
|
+
os.path.join(schema_path, json_filename), "w"
|
|
145
|
+
) as f:
|
|
146
|
+
json.dump(
|
|
147
|
+
simplified_schema,
|
|
148
|
+
f,
|
|
149
|
+
cls=DjangoJSONEncoder,
|
|
150
|
+
indent=2,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
index_exports.append(
|
|
154
|
+
f"export const {schema_var_name} = (() => import('./schemas/{json_filename}')) as SchemaLoader;"
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# B. Generate TypeScript
|
|
158
|
+
interface_code = global_ts_gen.generate_interface(
|
|
159
|
+
model_name, view_instance
|
|
160
|
+
)
|
|
161
|
+
if interface_code:
|
|
162
|
+
all_interfaces.append(interface_code)
|
|
163
|
+
break
|
|
164
|
+
except ImportError:
|
|
165
|
+
pass
|
|
166
|
+
except Exception as e:
|
|
167
|
+
print(f"--- Error loading module: {module_str} ---")
|
|
168
|
+
traceback.print_exc()
|
|
169
|
+
|
|
170
|
+
# Generate Imports for Types
|
|
171
|
+
imports = [
|
|
172
|
+
"import { ChoiceItem } from 'drf-react-by-schema';",
|
|
173
|
+
"import dayjs from 'dayjs';",
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
# Shared definitions
|
|
177
|
+
shared_defs = []
|
|
178
|
+
|
|
179
|
+
# Combine Type content
|
|
180
|
+
# Enums first
|
|
181
|
+
enums_content = list(global_ts_gen.enums.values())
|
|
182
|
+
|
|
183
|
+
types_content = ImportsAndContent(
|
|
184
|
+
imports, shared_defs + enums_content + all_interfaces
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Write Files
|
|
188
|
+
self.write_file(output_dir, "types.ts", types_content)
|
|
189
|
+
|
|
190
|
+
# Generate OptionsGetters
|
|
191
|
+
# Imports from types
|
|
192
|
+
enum_names = list(global_ts_gen.enums.keys())
|
|
193
|
+
getter_imports = []
|
|
194
|
+
if enum_names:
|
|
195
|
+
getter_imports.append(
|
|
196
|
+
f"import {{ {', '.join(sorted(enum_names))} }} from './types';"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
getter_funcs = []
|
|
200
|
+
for enum_name, labels_map in global_ts_gen.enum_labels.items():
|
|
201
|
+
func_name = f"get{enum_name}Label"
|
|
202
|
+
lines = [
|
|
203
|
+
f"export function {func_name}(value: {enum_name} | null | undefined): string {{"
|
|
204
|
+
]
|
|
205
|
+
lines.append(" if (value === null || value === undefined) return '';")
|
|
206
|
+
lines.append(" switch (value) {")
|
|
207
|
+
|
|
208
|
+
for val, label in labels_map.items():
|
|
209
|
+
# Value must match the enum definition in types.ts
|
|
210
|
+
# We used the same logic for keys in typescript_generator, but here we just need raw value for case
|
|
211
|
+
if isinstance(val, (int, float)):
|
|
212
|
+
case_val = f"{val}"
|
|
213
|
+
else:
|
|
214
|
+
# Escape quotes if string
|
|
215
|
+
safe_val = str(val).replace("'", "\\'")
|
|
216
|
+
case_val = f"'{safe_val}'"
|
|
217
|
+
|
|
218
|
+
# Escape label
|
|
219
|
+
safe_label = str(label).replace("'", "\\'").replace("\n", " ")
|
|
220
|
+
lines.append(f" case {case_val}: return '{safe_label}';")
|
|
221
|
+
|
|
222
|
+
lines.append(" default: return '';")
|
|
223
|
+
lines.append(" }")
|
|
224
|
+
lines.append("}")
|
|
225
|
+
getter_funcs.append("\n".join(lines))
|
|
226
|
+
|
|
227
|
+
# Export to index
|
|
228
|
+
# NO: these functions breach the SchemaType which are in the json files.
|
|
229
|
+
# index_exports.append(f"export * from './optionsGetters';")
|
|
230
|
+
|
|
231
|
+
getter_content_list = ImportsAndContent(getter_imports, getter_funcs)
|
|
232
|
+
self.write_file(output_dir, "optionsGetters.ts", getter_content_list)
|
|
233
|
+
|
|
234
|
+
# Write Index
|
|
235
|
+
# Dedup index exports
|
|
236
|
+
index_exports = list(dict.fromkeys(index_exports))
|
|
237
|
+
self.write_file(output_dir, "index.ts", index_exports)
|
|
238
|
+
|
|
239
|
+
self.stdout.write(
|
|
240
|
+
self.style.SUCCESS("Successfully synchronized schemas and types!")
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
def write_file(self, path, filename, content_list, custom_header=""):
|
|
244
|
+
full_path = os.path.join(path, filename)
|
|
245
|
+
if isinstance(content_list, ImportsAndContent):
|
|
246
|
+
content_str = content_list.to_string()
|
|
247
|
+
else:
|
|
248
|
+
content_str = "\n\n".join(content_list)
|
|
249
|
+
|
|
250
|
+
with open(full_path, "w") as f:
|
|
251
|
+
f.write("/* eslint-disable */\n")
|
|
252
|
+
f.write("// @generated by drf-react-by-schema\n\n")
|
|
253
|
+
if custom_header:
|
|
254
|
+
f.write(custom_header + "\n\n")
|
|
255
|
+
f.write(content_str)
|
|
256
|
+
f.write("\n")
|
|
257
|
+
|
|
258
|
+
def to_ts_literal(self, data, level=0):
|
|
259
|
+
# Kept for backward compatibility if other parts need it,
|
|
260
|
+
# but mostly unused for schema generation now
|
|
261
|
+
indent = " " * level
|
|
262
|
+
|
|
263
|
+
if isinstance(data, dict):
|
|
264
|
+
if not data:
|
|
265
|
+
return "{}"
|
|
266
|
+
lines = []
|
|
267
|
+
for key, value in data.items():
|
|
268
|
+
key = force_str(key)
|
|
269
|
+
if not key.isidentifier():
|
|
270
|
+
key = f"'{key}'"
|
|
271
|
+
val_str = self.to_ts_literal(value, level + 1)
|
|
272
|
+
lines.append(f"{indent} {key}: {val_str},")
|
|
273
|
+
return f"{{\n" + "\n".join(lines) + f"\n{indent}}}"
|
|
274
|
+
|
|
275
|
+
elif isinstance(data, (list, tuple)):
|
|
276
|
+
if not data:
|
|
277
|
+
return "[]"
|
|
278
|
+
# Multiline if any item is a dict or list or tuple
|
|
279
|
+
is_complex = any(isinstance(x, (dict, list, tuple)) for x in data)
|
|
280
|
+
items = [self.to_ts_literal(x, level + 1) for x in data]
|
|
281
|
+
if is_complex:
|
|
282
|
+
content = "\n".join([f"{indent} {x}," for x in items])
|
|
283
|
+
return f"[\n{content}\n{indent}]"
|
|
284
|
+
return f"[{', '.join(items)}]"
|
|
285
|
+
|
|
286
|
+
elif isinstance(data, bool):
|
|
287
|
+
return "true" if data else "false"
|
|
288
|
+
|
|
289
|
+
elif data is None:
|
|
290
|
+
return "null"
|
|
291
|
+
|
|
292
|
+
elif isinstance(data, (int, float)):
|
|
293
|
+
return str(data)
|
|
294
|
+
|
|
295
|
+
# Fallback for strings and anything else (including lazy objects)
|
|
296
|
+
val_str = force_str(data)
|
|
297
|
+
|
|
298
|
+
# If string contains single quote but NO double quote -> Use Double Quotes
|
|
299
|
+
# This makes strings like "('a', 'b')" cleaner: "('a', 'b')" instead of '(\'a\', \'b\')'
|
|
300
|
+
if "'" in val_str and '"' not in val_str:
|
|
301
|
+
safe_str = val_str.replace("\\", "\\\\").replace("\n", "\\n")
|
|
302
|
+
return f'"{safe_str}"'
|
|
303
|
+
|
|
304
|
+
# Default: Use Single Quotes
|
|
305
|
+
# Note: We must escape backslashes first, otherwise we might double-escape the ones added for quotes/newlines
|
|
306
|
+
safe_str = (
|
|
307
|
+
val_str.replace("\\", "\\\\").replace("\n", "\\n").replace("'", "\\'")
|
|
308
|
+
)
|
|
309
|
+
return f"'{safe_str}'"
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
class ImportsAndContent:
|
|
313
|
+
def __init__(self, imports, content):
|
|
314
|
+
self.imports = imports
|
|
315
|
+
self.content = content
|
|
316
|
+
|
|
317
|
+
def to_string(self):
|
|
318
|
+
return "\n".join(self.imports) + "\n\n" + "\n\n".join(self.content)
|
|
@@ -112,10 +112,15 @@ class Metadata(SimpleMetadata):
|
|
|
112
112
|
elif getattr(field, "auto_now_add", False) or getattr(
|
|
113
113
|
field, "auto_now", None
|
|
114
114
|
):
|
|
115
|
+
# metadata["actions"]["POST"][field_name]["model_default"] = (
|
|
116
|
+
# date.today()
|
|
117
|
+
# if isinstance(field, models.DateField)
|
|
118
|
+
# else datetime.now()
|
|
119
|
+
# )
|
|
115
120
|
metadata["actions"]["POST"][field_name]["model_default"] = (
|
|
116
|
-
|
|
121
|
+
"{dateNow}"
|
|
117
122
|
if isinstance(field, models.DateField)
|
|
118
|
-
else
|
|
123
|
+
else "{dateTimeNow}"
|
|
119
124
|
)
|
|
120
125
|
elif serializer_field and serializer_field.default:
|
|
121
126
|
if isinstance(serializer_field.default, (int, str)):
|
|
@@ -125,7 +130,7 @@ class Metadata(SimpleMetadata):
|
|
|
125
130
|
elif isinstance(serializer_field.default, CurrentUserDefault):
|
|
126
131
|
metadata["actions"]["POST"][field_name][
|
|
127
132
|
"model_default"
|
|
128
|
-
] = "currentUser"
|
|
133
|
+
] = "{currentUser}"
|
|
129
134
|
|
|
130
135
|
# Custom regex Validators:
|
|
131
136
|
validators = getattr(field, "validators", [])
|
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/serializers.py
RENAMED
|
@@ -80,11 +80,13 @@ class GenericSerializerMetaclass(SerializerMetaclass):
|
|
|
80
80
|
# Help text and label
|
|
81
81
|
help_text = getattr(field, "help_text", "")
|
|
82
82
|
verbose_name = getattr(field, "verbose_name", "")
|
|
83
|
-
if
|
|
83
|
+
if not verbose_name and getattr(
|
|
84
|
+
field.related_model._meta, "verbose_name", None
|
|
85
|
+
):
|
|
84
86
|
verbose_name = getattr(
|
|
85
87
|
field.related_model._meta, "verbose_name", None
|
|
86
88
|
)
|
|
87
|
-
elif verbose_name
|
|
89
|
+
elif not verbose_name:
|
|
88
90
|
verbose_name = field.related_model.__name__
|
|
89
91
|
|
|
90
92
|
# Reverse relations don't use null/blank the same way
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema.egg-info/SOURCES.txt
RENAMED
|
@@ -35,6 +35,9 @@ drf_react_by_schema/fields/number.py
|
|
|
35
35
|
drf_react_by_schema/fields/relational.py
|
|
36
36
|
drf_react_by_schema/fields/serializers.py
|
|
37
37
|
drf_react_by_schema/fields/text.py
|
|
38
|
+
drf_react_by_schema/management/__init__.py
|
|
39
|
+
drf_react_by_schema/management/commands/__init__.py
|
|
40
|
+
drf_react_by_schema/management/commands/sync_react.py
|
|
38
41
|
drf_react_by_schema/migrations/__init__.py
|
|
39
42
|
drf_react_by_schema/patches/__init__.py
|
|
40
43
|
drf_react_by_schema/patches/drf_serializers.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/__init__.py
RENAMED
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/array.py
RENAMED
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/boolean.py
RENAMED
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/date.py
RENAMED
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/file.py
RENAMED
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/number.py
RENAMED
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/relational.py
RENAMED
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/serializers.py
RENAMED
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/fields/text.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/patches/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema/utils_cache.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema.egg-info/requires.txt
RENAMED
|
File without changes
|
{drf_react_by_schema-0.26.0 → drf_react_by_schema-0.26.2}/drf_react_by_schema.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|