drf-to-mkdoc 0.2.0__py3-none-any.whl → 0.2.2__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.
Potentially problematic release.
This version of drf-to-mkdoc might be problematic. Click here for more details.
- drf_to_mkdoc/conf/defaults.py +5 -0
- drf_to_mkdoc/conf/settings.py +121 -9
- drf_to_mkdoc/management/commands/build_docs.py +8 -7
- drf_to_mkdoc/management/commands/build_endpoint_docs.py +69 -0
- drf_to_mkdoc/management/commands/build_model_docs.py +50 -0
- drf_to_mkdoc/management/commands/{generate_model_docs.py → extract_model_data.py} +14 -19
- drf_to_mkdoc/templates/endpoints/detail/base.html +33 -0
- drf_to_mkdoc/templates/endpoints/detail/path_parameters.html +8 -0
- drf_to_mkdoc/templates/endpoints/detail/query_parameters.html +43 -0
- drf_to_mkdoc/templates/endpoints/detail/request_body.html +10 -0
- drf_to_mkdoc/templates/endpoints/detail/responses.html +18 -0
- drf_to_mkdoc/templates/endpoints/list/base.html +23 -0
- drf_to_mkdoc/templates/endpoints/list/endpoint_card.html +18 -0
- drf_to_mkdoc/templates/endpoints/list/filter_section.html +16 -0
- drf_to_mkdoc/templates/endpoints/list/filters/app.html +8 -0
- drf_to_mkdoc/templates/endpoints/list/filters/method.html +12 -0
- drf_to_mkdoc/templates/endpoints/list/filters/path.html +5 -0
- drf_to_mkdoc/templates/endpoints/list/filters/search.html +9 -0
- drf_to_mkdoc/templates/model_detail/base.html +34 -0
- drf_to_mkdoc/templates/model_detail/choices.html +12 -0
- drf_to_mkdoc/templates/model_detail/fields.html +11 -0
- drf_to_mkdoc/templates/model_detail/meta.html +6 -0
- drf_to_mkdoc/templates/model_detail/methods.html +9 -0
- drf_to_mkdoc/templates/model_detail/relationships.html +8 -0
- drf_to_mkdoc/templates/models_index.html +24 -0
- drf_to_mkdoc/templatetags/custom_filters.py +116 -0
- drf_to_mkdoc/utils/ai_tools/enums.py +13 -0
- drf_to_mkdoc/utils/ai_tools/exceptions.py +19 -0
- drf_to_mkdoc/utils/ai_tools/providers/__init__.py +0 -0
- drf_to_mkdoc/utils/ai_tools/providers/base_provider.py +123 -0
- drf_to_mkdoc/utils/ai_tools/providers/gemini_provider.py +80 -0
- drf_to_mkdoc/utils/ai_tools/types.py +81 -0
- drf_to_mkdoc/utils/commons/__init__.py +0 -0
- drf_to_mkdoc/utils/commons/code_extractor.py +22 -0
- drf_to_mkdoc/utils/commons/file_utils.py +35 -0
- drf_to_mkdoc/utils/commons/model_utils.py +83 -0
- drf_to_mkdoc/utils/commons/operation_utils.py +83 -0
- drf_to_mkdoc/utils/commons/path_utils.py +78 -0
- drf_to_mkdoc/utils/commons/schema_utils.py +230 -0
- drf_to_mkdoc/utils/endpoint_detail_generator.py +86 -202
- drf_to_mkdoc/utils/endpoint_list_generator.py +59 -194
- drf_to_mkdoc/utils/extractors/query_parameter_extractors.py +33 -30
- drf_to_mkdoc/utils/model_detail_generator.py +37 -211
- drf_to_mkdoc/utils/model_list_generator.py +38 -46
- drf_to_mkdoc/utils/schema.py +259 -0
- {drf_to_mkdoc-0.2.0.dist-info → drf_to_mkdoc-0.2.2.dist-info}/METADATA +16 -5
- drf_to_mkdoc-0.2.2.dist-info/RECORD +85 -0
- drf_to_mkdoc/management/commands/generate_docs.py +0 -113
- drf_to_mkdoc/utils/common.py +0 -353
- drf_to_mkdoc/utils/md_generators/query_parameters_generators.py +0 -72
- drf_to_mkdoc-0.2.0.dist-info/RECORD +0 -52
- /drf_to_mkdoc/utils/{md_generators → ai_tools}/__init__.py +0 -0
- {drf_to_mkdoc-0.2.0.dist-info → drf_to_mkdoc-0.2.2.dist-info}/WHEEL +0 -0
- {drf_to_mkdoc-0.2.0.dist-info → drf_to_mkdoc-0.2.2.dist-info}/licenses/LICENSE +0 -0
- {drf_to_mkdoc-0.2.0.dist-info → drf_to_mkdoc-0.2.2.dist-info}/top_level.txt +0 -0
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
from drf_to_mkdoc.utils.common import extract_viewset_from_operation_id
|
|
3
|
+
from drf_to_mkdoc.utils.commons.operation_utils import extract_viewset_from_operation_id
|
|
6
4
|
|
|
7
5
|
|
|
8
6
|
def extract_query_parameters_from_view(operation_id: str) -> dict[str, Any]:
|
|
@@ -111,35 +109,34 @@ def extract_query_parameters_from_view_pagination_fields(view_class: Any) -> lis
|
|
|
111
109
|
|
|
112
110
|
|
|
113
111
|
def _extract_filterset_fields_from_class_attributes(filterset_class: Any) -> list[str]:
|
|
114
|
-
fields = []
|
|
115
|
-
|
|
116
112
|
try:
|
|
117
|
-
#
|
|
118
|
-
for attr_name in dir(filterset_class):
|
|
119
|
-
# Skip private attributes and known non-filter attributes
|
|
120
|
-
if attr_name.startswith("_") or attr_name in [
|
|
121
|
-
"Meta",
|
|
122
|
-
"form",
|
|
123
|
-
"queryset",
|
|
124
|
-
"request",
|
|
125
|
-
"errors",
|
|
126
|
-
"qs",
|
|
127
|
-
"is_valid",
|
|
128
|
-
]:
|
|
129
|
-
continue
|
|
130
|
-
|
|
131
|
-
try:
|
|
132
|
-
attr = getattr(filterset_class, attr_name)
|
|
133
|
-
if isinstance(attr, django_filters.Filter):
|
|
134
|
-
if attr_name not in fields:
|
|
135
|
-
fields.append(attr_name)
|
|
136
|
-
except (AttributeError, TypeError):
|
|
137
|
-
continue
|
|
138
|
-
|
|
113
|
+
import django_filters # noqa: PLC0415
|
|
139
114
|
except ImportError:
|
|
140
115
|
# django_filters not available, skip this strategy
|
|
141
|
-
|
|
116
|
+
return []
|
|
142
117
|
|
|
118
|
+
fields = []
|
|
119
|
+
# Get all class attributes, including inherited ones
|
|
120
|
+
for attr_name in dir(filterset_class):
|
|
121
|
+
# Skip private attributes and known non-filter attributes
|
|
122
|
+
if attr_name.startswith("_") or attr_name in [
|
|
123
|
+
"Meta",
|
|
124
|
+
"form",
|
|
125
|
+
"queryset",
|
|
126
|
+
"request",
|
|
127
|
+
"errors",
|
|
128
|
+
"qs",
|
|
129
|
+
"is_valid",
|
|
130
|
+
]:
|
|
131
|
+
continue
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
attr = getattr(filterset_class, attr_name)
|
|
135
|
+
if isinstance(attr, django_filters.Filter):
|
|
136
|
+
if attr_name not in fields:
|
|
137
|
+
fields.append(attr_name)
|
|
138
|
+
except (AttributeError, TypeError):
|
|
139
|
+
continue
|
|
143
140
|
return fields
|
|
144
141
|
|
|
145
142
|
|
|
@@ -182,7 +179,8 @@ def _extract_filterset_fields_from_internal_attrs(filterset_class: Any) -> list[
|
|
|
182
179
|
|
|
183
180
|
|
|
184
181
|
def _extract_filterset_fields_from_get_fields(filterset_class: Any) -> list[str]:
|
|
185
|
-
|
|
182
|
+
meta = getattr(filterset_class, "_meta", None)
|
|
183
|
+
if not getattr(meta, "model", None):
|
|
186
184
|
# If the Meta class is not defined in the Filter class,
|
|
187
185
|
# the get_fields function is raise error
|
|
188
186
|
return []
|
|
@@ -191,7 +189,12 @@ def _extract_filterset_fields_from_get_fields(filterset_class: Any) -> list[str]
|
|
|
191
189
|
if not hasattr(filterset_class, "get_fields"):
|
|
192
190
|
return []
|
|
193
191
|
|
|
194
|
-
|
|
192
|
+
try:
|
|
193
|
+
filterset_instance = filterset_class()
|
|
194
|
+
except TypeError:
|
|
195
|
+
# Constructor requires args; skip dynamic field discovery
|
|
196
|
+
return []
|
|
197
|
+
|
|
195
198
|
filterset_fields = filterset_instance.get_fields()
|
|
196
199
|
if not (filterset_fields and hasattr(filterset_fields, "keys")):
|
|
197
200
|
return []
|
|
@@ -1,83 +1,31 @@
|
|
|
1
1
|
from typing import Any
|
|
2
2
|
|
|
3
|
+
from django.template.loader import render_to_string
|
|
3
4
|
from django.templatetags.static import static
|
|
4
5
|
|
|
5
6
|
from drf_to_mkdoc.conf.settings import drf_to_mkdoc_settings
|
|
6
|
-
from drf_to_mkdoc.utils.
|
|
7
|
+
from drf_to_mkdoc.utils.commons.file_utils import write_file
|
|
8
|
+
from drf_to_mkdoc.utils.commons.model_utils import get_model_description
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
def generate_model_docs(models_data: dict[str, Any]) -> None:
|
|
10
12
|
"""Generate model documentation from JSON data"""
|
|
11
|
-
for
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
for app_name, models in models_data.items():
|
|
14
|
+
if not isinstance(models, dict):
|
|
15
|
+
raise TypeError(f"Expected dict for models in app '{app_name}', got {type(models)}")
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
for model_name, model_info in models.items():
|
|
18
|
+
if not isinstance(model_info, dict) or "name" not in model_info:
|
|
19
|
+
raise ValueError(
|
|
20
|
+
f"Model info for '{model_name}' in app '{app_name}' is invalid"
|
|
21
|
+
)
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
write_file(file_path, content)
|
|
23
|
+
# Create the model page content
|
|
24
|
+
content = create_model_page(model_info)
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
content = "## Fields\n\n"
|
|
26
|
-
content += "| Field | Type | Description | Extra |\n"
|
|
27
|
-
content += "|-------|------|-------------|-------|\n"
|
|
28
|
-
|
|
29
|
-
for field_name, field_info in fields.items():
|
|
30
|
-
field_type = field_info.get("type", "Unknown")
|
|
31
|
-
verbose_name = field_info.get("verbose_name", field_name)
|
|
32
|
-
help_text = field_info.get("help_text", "")
|
|
33
|
-
|
|
34
|
-
display_name = field_name
|
|
35
|
-
if field_type in ["ForeignKey", "OneToOneField"]:
|
|
36
|
-
display_name = f"{field_name}_id"
|
|
37
|
-
|
|
38
|
-
extra_info = []
|
|
39
|
-
if field_info.get("null"):
|
|
40
|
-
extra_info.append("null=True")
|
|
41
|
-
if field_info.get("blank"):
|
|
42
|
-
extra_info.append("blank=True")
|
|
43
|
-
if field_info.get("unique"):
|
|
44
|
-
extra_info.append("unique=True")
|
|
45
|
-
if field_info.get("primary_key"):
|
|
46
|
-
extra_info.append("primary_key=True")
|
|
47
|
-
if field_info.get("default"):
|
|
48
|
-
extra_info.append(f"default={field_info['default']}")
|
|
49
|
-
|
|
50
|
-
field_specific = field_info.get("field_specific", {})
|
|
51
|
-
for key, value in field_specific.items():
|
|
52
|
-
if key not in ["related_name", "related_query_name", "to"]:
|
|
53
|
-
extra_info.append(f"{key}={value}")
|
|
54
|
-
|
|
55
|
-
extra_str = ", ".join(extra_info) if extra_info else ""
|
|
56
|
-
description_str = help_text or verbose_name
|
|
57
|
-
|
|
58
|
-
content += f"| `{display_name}` | {field_type} | {description_str} | {extra_str} |\n"
|
|
59
|
-
|
|
60
|
-
return content
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def render_choices_tables(fields: dict[str, Any]) -> str:
|
|
64
|
-
"""Render choice tables for fields with choices."""
|
|
65
|
-
choice_tables = []
|
|
66
|
-
|
|
67
|
-
for field_name, field_info in fields.items():
|
|
68
|
-
choices = field_info.get("choices")
|
|
69
|
-
if choices:
|
|
70
|
-
table = f"### {field_name} Choices\n\n"
|
|
71
|
-
table += "| Label | Value |\n"
|
|
72
|
-
table += "|-------|--------|\n"
|
|
73
|
-
for choice in choices:
|
|
74
|
-
table += f"| {choice['display']} | `{choice['value']}` |\n"
|
|
75
|
-
table += "\n"
|
|
76
|
-
choice_tables.append(table)
|
|
77
|
-
|
|
78
|
-
if choice_tables:
|
|
79
|
-
return "## Choices\n\n" + "\n".join(choice_tables)
|
|
80
|
-
return ""
|
|
26
|
+
# Write the file in app subdirectory
|
|
27
|
+
file_path = f"models/{app_name}/{model_info['table_name']}.md"
|
|
28
|
+
write_file(file_path, content)
|
|
81
29
|
|
|
82
30
|
|
|
83
31
|
def create_model_page(model_info: dict[str, Any]) -> str:
|
|
@@ -86,151 +34,29 @@ def create_model_page(model_info: dict[str, Any]) -> str:
|
|
|
86
34
|
app_label = model_info.get("app_label", "unknown")
|
|
87
35
|
table_name = model_info.get("table_name", "")
|
|
88
36
|
description = get_model_description(name)
|
|
37
|
+
column_fields = model_info.get("column_fields", {})
|
|
89
38
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
content += _add_relationships_section(model_info)
|
|
93
|
-
content += _add_methods_section(model_info)
|
|
94
|
-
content += _add_meta_options_section(model_info)
|
|
95
|
-
|
|
96
|
-
return content
|
|
97
|
-
|
|
39
|
+
# Check if any fields have choices
|
|
40
|
+
has_choices = any(field_info.get("choices") for field_info in column_fields.values())
|
|
98
41
|
|
|
99
|
-
def _create_model_header(name: str, app_label: str, table_name: str, description: str) -> str:
|
|
100
|
-
"""Create the header section of the model documentation."""
|
|
101
42
|
stylesheets = [
|
|
102
|
-
"stylesheets/models/variables.css",
|
|
103
|
-
"stylesheets/models/base.css",
|
|
104
|
-
"stylesheets/models/model-tables.css",
|
|
105
|
-
"stylesheets/models/responsive.css",
|
|
43
|
+
static(f"{drf_to_mkdoc_settings.PROJECT_NAME}/stylesheets/models/variables.css"),
|
|
44
|
+
static(f"{drf_to_mkdoc_settings.PROJECT_NAME}/stylesheets/models/base.css"),
|
|
45
|
+
static(f"{drf_to_mkdoc_settings.PROJECT_NAME}/stylesheets/models/model-tables.css"),
|
|
46
|
+
static(f"{drf_to_mkdoc_settings.PROJECT_NAME}/stylesheets/models/responsive.css"),
|
|
106
47
|
]
|
|
107
|
-
prefix_path = f"{drf_to_mkdoc_settings.PROJECT_NAME}/"
|
|
108
|
-
css_links = "\n".join(
|
|
109
|
-
f'<link rel="stylesheet" href="{static(prefix_path + path)}">' for path in stylesheets
|
|
110
|
-
)
|
|
111
|
-
return f"""# {name}
|
|
112
|
-
|
|
113
|
-
<!-- inject CSS directly -->
|
|
114
|
-
{css_links}
|
|
115
|
-
|
|
116
|
-
**App:** {app_label}
|
|
117
|
-
**Table:** `{table_name}`
|
|
118
|
-
|
|
119
|
-
## Description
|
|
120
|
-
|
|
121
|
-
{description}
|
|
122
|
-
|
|
123
|
-
"""
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def _add_fields_section(model_info: dict[str, Any]) -> str:
|
|
127
|
-
"""Add the fields section to the model documentation."""
|
|
128
|
-
column_fields = model_info.get("column_fields", {})
|
|
129
|
-
if not column_fields:
|
|
130
|
-
return ""
|
|
131
|
-
|
|
132
|
-
content = ""
|
|
133
|
-
|
|
134
|
-
column_fields_content = render_column_fields_table(column_fields)
|
|
135
|
-
if column_fields_content:
|
|
136
|
-
content += column_fields_content
|
|
137
|
-
content += "\n"
|
|
138
|
-
|
|
139
|
-
choices_content = render_choices_tables(column_fields)
|
|
140
|
-
if choices_content:
|
|
141
|
-
content += choices_content
|
|
142
|
-
content += "\n"
|
|
143
|
-
|
|
144
|
-
return content
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
def _add_relationships_section(model_info: dict[str, Any]) -> str:
|
|
148
|
-
"""Add the relationships section to the model documentation."""
|
|
149
|
-
relationship_fields = model_info.get("relationships", {})
|
|
150
|
-
if not relationship_fields:
|
|
151
|
-
return ""
|
|
152
|
-
|
|
153
|
-
content = "## Relationships\n\n"
|
|
154
|
-
content += "| Field | Type | Related Model |\n"
|
|
155
|
-
content += "|-------|------|---------------|\n"
|
|
156
|
-
|
|
157
|
-
content += _render_relationship_fields(relationship_fields)
|
|
158
|
-
content += _render_relationships_from_section(relationship_fields)
|
|
159
|
-
content += "\n"
|
|
160
|
-
|
|
161
|
-
return content
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
def _render_relationship_fields(relationship_fields: dict[str, Any]) -> str:
|
|
165
|
-
"""Render relationship fields from the fields section."""
|
|
166
|
-
content = ""
|
|
167
|
-
for field_name, field_info in relationship_fields.items():
|
|
168
|
-
field_type = field_info.get("type", "Unknown")
|
|
169
|
-
field_specific = field_info.get("field_specific", {})
|
|
170
|
-
to_model = field_specific.get("to", "")
|
|
171
|
-
|
|
172
|
-
if to_model:
|
|
173
|
-
model_link = _create_model_link(to_model)
|
|
174
|
-
content += f"| `{field_name}` | {field_type} | {model_link}|\n"
|
|
175
|
-
|
|
176
|
-
return content
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
def _render_relationships_from_section(relationships: dict[str, Any]) -> str:
|
|
180
|
-
"""Render relationships from the relationships section."""
|
|
181
|
-
content = ""
|
|
182
|
-
for rel_name, rel_info in relationships.items():
|
|
183
|
-
rel_type = rel_info.get("type", "Unknown")
|
|
184
|
-
related_model_full = rel_info.get("related_model", "")
|
|
185
|
-
|
|
186
|
-
if related_model_full and "." in related_model_full:
|
|
187
|
-
related_app, related_model = related_model_full.split(".", 1)
|
|
188
|
-
model_link = f"[{related_model}](../../{related_app}/{related_model.lower()}/)"
|
|
189
|
-
else:
|
|
190
|
-
model_link = related_model_full
|
|
191
|
-
|
|
192
|
-
content += f"| `{rel_name}` | {rel_type} | {model_link} | \n"
|
|
193
|
-
|
|
194
|
-
return content
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def _create_model_link(to_model: str) -> str:
|
|
198
|
-
"""Create a link to a related model."""
|
|
199
|
-
if "." in to_model:
|
|
200
|
-
related_app, related_model = to_model.split(".", 1)
|
|
201
|
-
return f"[{related_model}](../{related_app}/{related_model.lower()}/)"
|
|
202
|
-
return f"[{to_model}]({to_model.lower()}/)"
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
def _add_methods_section(model_info: dict[str, Any]) -> str:
|
|
206
|
-
"""Add the methods section to the model documentation."""
|
|
207
|
-
methods = model_info.get("methods", [])
|
|
208
|
-
if not methods:
|
|
209
|
-
return ""
|
|
210
|
-
|
|
211
|
-
content = "## Methods\n\n"
|
|
212
|
-
for method in methods:
|
|
213
|
-
method_name = method.get("name", "")
|
|
214
|
-
docstring = method.get("docstring", "")
|
|
215
|
-
|
|
216
|
-
content += f"### `{method_name}()`\n\n"
|
|
217
|
-
if docstring:
|
|
218
|
-
content += f"{docstring}\n\n"
|
|
219
|
-
else:
|
|
220
|
-
content += "No documentation available.\n\n"
|
|
221
|
-
|
|
222
|
-
return content
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
def _add_meta_options_section(model_info: dict[str, Any]) -> str:
|
|
226
|
-
"""Add the meta options section to the model documentation."""
|
|
227
|
-
meta_options = model_info.get("meta_options", {})
|
|
228
|
-
if not meta_options:
|
|
229
|
-
return ""
|
|
230
|
-
|
|
231
|
-
content = "## Meta Options\n\n"
|
|
232
|
-
for option, value in meta_options.items():
|
|
233
|
-
content += f"- **{option}:** {value}\n"
|
|
234
|
-
content += "\n"
|
|
235
48
|
|
|
236
|
-
|
|
49
|
+
context = {
|
|
50
|
+
"name": name,
|
|
51
|
+
"app_label": app_label,
|
|
52
|
+
"table_name": table_name,
|
|
53
|
+
"description": description,
|
|
54
|
+
"stylesheets": stylesheets,
|
|
55
|
+
"fields": column_fields, # Changed from column_fields to fields for template consistency
|
|
56
|
+
"has_choices": has_choices, # Added choices flag
|
|
57
|
+
"relationships": model_info.get("relationships", {}),
|
|
58
|
+
"methods": model_info.get("methods", []),
|
|
59
|
+
"meta_options": model_info.get("meta_options", {}),
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return render_to_string("model_detail/base.html", context)
|
|
@@ -1,64 +1,56 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
2
|
from typing import Any
|
|
3
3
|
|
|
4
|
+
from django.template.loader import render_to_string
|
|
4
5
|
from django.templatetags.static import static
|
|
5
6
|
|
|
6
7
|
from drf_to_mkdoc.conf.settings import drf_to_mkdoc_settings
|
|
7
|
-
from drf_to_mkdoc.utils.
|
|
8
|
+
from drf_to_mkdoc.utils.commons.model_utils import get_app_descriptions
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def create_models_index(models_data: dict[str, Any], docs_dir: Path) -> None:
|
|
11
12
|
"""Create the main models index page that lists all models organized by app."""
|
|
12
|
-
models_by_app = {}
|
|
13
|
-
for model_name, model_info in models_data.items():
|
|
14
|
-
app_name = model_info.get("app_label", model_name.split(".")[0])
|
|
15
|
-
class_name = model_info.get("name", model_name.split(".")[-1])
|
|
16
|
-
if app_name not in models_by_app:
|
|
17
|
-
models_by_app[app_name] = []
|
|
18
|
-
models_by_app[app_name].append((class_name, model_name, model_info))
|
|
19
|
-
|
|
20
13
|
stylesheets = [
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
14
|
+
static(f"{drf_to_mkdoc_settings.PROJECT_NAME}/{path}")
|
|
15
|
+
for path in [
|
|
16
|
+
"stylesheets/models/variables.css",
|
|
17
|
+
"stylesheets/models/base.css",
|
|
18
|
+
"stylesheets/models/model-cards.css",
|
|
19
|
+
"stylesheets/models/responsive.css",
|
|
20
|
+
"stylesheets/models/animations.css",
|
|
21
|
+
]
|
|
26
22
|
]
|
|
27
|
-
prefix_path = f"{drf_to_mkdoc_settings.PROJECT_NAME}/"
|
|
28
|
-
css_links = "\n".join(
|
|
29
|
-
f'<link rel="stylesheet" href="{static(prefix_path + path)}">' for path in stylesheets
|
|
30
|
-
)
|
|
31
|
-
content = f"""# Django Models
|
|
32
|
-
|
|
33
|
-
This section contains documentation for all Django models in the system, organized by Django application.
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
24
|
+
sorted_models = []
|
|
25
|
+
for app_name, models in sorted(models_data.items()):
|
|
26
|
+
model_names = sorted(
|
|
27
|
+
[
|
|
28
|
+
(
|
|
29
|
+
str(mi.get("verbose_name") or mk).capitalize(),
|
|
30
|
+
str(mi.get("table_name") or mk),
|
|
31
|
+
)
|
|
32
|
+
for mk, mi in models.items()
|
|
33
|
+
if isinstance(mi, dict)
|
|
34
|
+
],
|
|
35
|
+
key=lambda x: x[0].casefold(),
|
|
36
|
+
)
|
|
37
|
+
sorted_models.append((app_name, model_names))
|
|
40
38
|
|
|
41
39
|
app_descriptions = get_app_descriptions()
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
content += "</div>\n\n"
|
|
57
|
-
|
|
58
|
-
content += """</div>
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Each model page contains detailed field documentation, method signatures, and relationships to other models."""
|
|
40
|
+
for app_name, _ in sorted_models:
|
|
41
|
+
if app_name not in app_descriptions:
|
|
42
|
+
app_descriptions[app_name] = (
|
|
43
|
+
f"{app_name.replace('_', ' ').title()} application models"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
content = render_to_string(
|
|
47
|
+
"models_index.html",
|
|
48
|
+
{
|
|
49
|
+
"stylesheets": stylesheets,
|
|
50
|
+
"sorted_models": sorted_models,
|
|
51
|
+
"app_descriptions": app_descriptions,
|
|
52
|
+
},
|
|
53
|
+
)
|
|
62
54
|
|
|
63
55
|
models_index_path = docs_dir / "models" / "index.md"
|
|
64
56
|
models_index_path.parent.mkdir(parents=True, exist_ok=True)
|