drf-to-mkdoc 0.1.0__py3-none-any.whl → 0.1.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/__init__.py +6 -6
- drf_to_mkdoc/apps.py +14 -14
- drf_to_mkdoc/conf/settings.py +44 -44
- drf_to_mkdoc/management/commands/build_docs.py +76 -76
- drf_to_mkdoc/management/commands/generate_doc_json.py +512 -512
- drf_to_mkdoc/management/commands/generate_docs.py +138 -138
- drf_to_mkdoc/management/commands/generate_model_docs.py +327 -327
- drf_to_mkdoc/management/commands/update_doc_schema.py +53 -53
- drf_to_mkdoc/utils/__init__.py +3 -3
- drf_to_mkdoc/utils/endpoint_generator.py +945 -945
- drf_to_mkdoc/utils/extractors/__init__.py +3 -3
- drf_to_mkdoc/utils/extractors/query_parameter_extractors.py +229 -229
- drf_to_mkdoc/utils/md_generators/query_parameters_generators.py +72 -72
- drf_to_mkdoc/utils/model_generator.py +269 -269
- {drf_to_mkdoc-0.1.0.dist-info → drf_to_mkdoc-0.1.2.dist-info}/METADATA +247 -247
- drf_to_mkdoc-0.1.2.dist-info/RECORD +25 -0
- {drf_to_mkdoc-0.1.0.dist-info → drf_to_mkdoc-0.1.2.dist-info}/licenses/LICENSE +21 -21
- drf_to_mkdoc-0.1.0.dist-info/RECORD +0 -25
- {drf_to_mkdoc-0.1.0.dist-info → drf_to_mkdoc-0.1.2.dist-info}/WHEEL +0 -0
- {drf_to_mkdoc-0.1.0.dist-info → drf_to_mkdoc-0.1.2.dist-info}/top_level.txt +0 -0
|
@@ -1,269 +1,269 @@
|
|
|
1
|
-
from pathlib import Path
|
|
2
|
-
from typing import Any
|
|
3
|
-
|
|
4
|
-
from drf_to_mkdoc.utils.common import get_app_descriptions, get_model_description, write_file
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def create_models_index(models_data: dict[str, Any], docs_dir: Path) -> None:
|
|
8
|
-
models_by_app = {}
|
|
9
|
-
for model_name, model_info in models_data.items():
|
|
10
|
-
app_name = model_info.get("app_label", model_name.split(".")[0])
|
|
11
|
-
class_name = model_info.get("name", model_name.split(".")[-1])
|
|
12
|
-
if app_name not in models_by_app:
|
|
13
|
-
models_by_app[app_name] = []
|
|
14
|
-
models_by_app[app_name].append((class_name, model_name, model_info))
|
|
15
|
-
|
|
16
|
-
content = """# Django Models\n\nThis section contains documentation for
|
|
17
|
-
all Django models in the system, organized by Django application.\n\n"""
|
|
18
|
-
|
|
19
|
-
app_descriptions = get_app_descriptions()
|
|
20
|
-
|
|
21
|
-
for app_name in sorted(models_by_app.keys()):
|
|
22
|
-
app_desc = app_descriptions.get(app_name, f"{app_name.title()} application models")
|
|
23
|
-
content += f'<div class="app-header">{app_name.title()} App</div>\n\n'
|
|
24
|
-
content += f"*{app_desc}*\n\n"
|
|
25
|
-
|
|
26
|
-
content += '<div class="model-cards">\n'
|
|
27
|
-
|
|
28
|
-
for class_name, _model_name, _model_info in sorted(models_by_app[app_name]):
|
|
29
|
-
content += f"""
|
|
30
|
-
<a href="{app_name}/{class_name.lower()}/"
|
|
31
|
-
class="model-card">{class_name}</a>\n
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
content += "</div>\n\n"
|
|
35
|
-
|
|
36
|
-
content += """## Model Relationships\n\nThe models are interconnected through foreign keys
|
|
37
|
-
and many-to-many relationships:\n\n- **Users** can be associated
|
|
38
|
-
with multiple **Clinics** through **ClinicUser**
|
|
39
|
-
\n- **Doctors** belong to **Clinics**
|
|
40
|
-
and offer **Services** through **DoctorService**
|
|
41
|
-
\n- **Appointments** connect **Patients**
|
|
42
|
-
with **Doctors** and **Services**
|
|
43
|
-
\n- **Schedules** define **Doctor** availability in specific **Rooms**
|
|
44
|
-
\n- **Rooms** belong to **Clinics** and host **Appointments**\n
|
|
45
|
-
\nEach model page contains detailed field documentation,
|
|
46
|
-
method signatures, and relationships to other models.\n"""
|
|
47
|
-
|
|
48
|
-
models_index_path = docs_dir / "models" / "index.md"
|
|
49
|
-
models_index_path.parent.mkdir(parents=True, exist_ok=True)
|
|
50
|
-
|
|
51
|
-
with models_index_path.open("w", encoding="utf-8") as f:
|
|
52
|
-
f.write(content)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def generate_model_docs(models_data: dict[str, Any]) -> None:
|
|
56
|
-
"""Generate model documentation from JSON data"""
|
|
57
|
-
for model_name, model_info in models_data.items():
|
|
58
|
-
app_name = model_info.get("app_label", model_name.split(".")[0])
|
|
59
|
-
class_name = model_info.get("name", model_name.split(".")[-1])
|
|
60
|
-
|
|
61
|
-
# Create the model page content
|
|
62
|
-
content = create_model_page(model_info)
|
|
63
|
-
|
|
64
|
-
# Write the file in app subdirectory
|
|
65
|
-
file_path = f"models/{app_name}/{class_name.lower()}.md"
|
|
66
|
-
write_file(file_path, content)
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def render_fields_table(fields: dict[str, Any]) -> str:
|
|
70
|
-
content = "## Fields\n\n"
|
|
71
|
-
content += "| Field | Type | Description | Extra |\n"
|
|
72
|
-
content += "|-------|------|-------------|-------|\n"
|
|
73
|
-
|
|
74
|
-
for field_name, field_info in fields.items():
|
|
75
|
-
field_type = field_info.get("type", "Unknown")
|
|
76
|
-
verbose_name = field_info.get("verbose_name", field_name)
|
|
77
|
-
help_text = field_info.get("help_text", "")
|
|
78
|
-
|
|
79
|
-
extra_info = []
|
|
80
|
-
if field_info.get("null"):
|
|
81
|
-
extra_info.append("null=True")
|
|
82
|
-
if field_info.get("blank"):
|
|
83
|
-
extra_info.append("blank=True")
|
|
84
|
-
if field_info.get("unique"):
|
|
85
|
-
extra_info.append("unique=True")
|
|
86
|
-
if field_info.get("primary_key"):
|
|
87
|
-
extra_info.append("primary_key=True")
|
|
88
|
-
if field_info.get("default"):
|
|
89
|
-
extra_info.append(f"default={field_info['default']}")
|
|
90
|
-
|
|
91
|
-
field_specific = field_info.get("field_specific", {})
|
|
92
|
-
for key, value in field_specific.items():
|
|
93
|
-
if key not in ["related_name", "related_query_name", "to"]:
|
|
94
|
-
extra_info.append(f"{key}={value}")
|
|
95
|
-
|
|
96
|
-
extra_str = ", ".join(extra_info) if extra_info else ""
|
|
97
|
-
description_str = help_text or verbose_name
|
|
98
|
-
|
|
99
|
-
content += f"| `{field_name}` | {field_type} | {description_str} | {extra_str} |\n"
|
|
100
|
-
|
|
101
|
-
return content
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
def render_choices_tables(fields: dict[str, Any]) -> str:
|
|
105
|
-
choice_tables = []
|
|
106
|
-
|
|
107
|
-
for field_name, field_info in fields.items():
|
|
108
|
-
choices = field_info.get("choices")
|
|
109
|
-
if choices:
|
|
110
|
-
table = f"### {field_name} Choices\n\n"
|
|
111
|
-
table += "| Label | Value |\n"
|
|
112
|
-
table += "|-------|--------|\n"
|
|
113
|
-
for choice in choices:
|
|
114
|
-
table += f"| {choice['display']} | `{choice['value']}` |\n"
|
|
115
|
-
table += "\n"
|
|
116
|
-
choice_tables.append(table)
|
|
117
|
-
|
|
118
|
-
if choice_tables:
|
|
119
|
-
return "## Choices\n\n" + "\n".join(choice_tables)
|
|
120
|
-
return ""
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def create_model_page(model_info: dict[str, Any]) -> str:
|
|
124
|
-
"""Create a model documentation page from model info"""
|
|
125
|
-
name = model_info.get("name", "Unknown")
|
|
126
|
-
app_label = model_info.get("app_label", "unknown")
|
|
127
|
-
table_name = model_info.get("table_name", "")
|
|
128
|
-
description = get_model_description(name)
|
|
129
|
-
|
|
130
|
-
content = _create_model_header(name, app_label, table_name, description)
|
|
131
|
-
content += _add_fields_section(model_info)
|
|
132
|
-
content += _add_relationships_section(model_info)
|
|
133
|
-
content += _add_methods_section(model_info)
|
|
134
|
-
content += _add_meta_options_section(model_info)
|
|
135
|
-
|
|
136
|
-
return content
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
def _create_model_header(name: str, app_label: str, table_name: str, description: str) -> str:
|
|
140
|
-
"""Create the header section of the model documentation."""
|
|
141
|
-
return f"""# {name}
|
|
142
|
-
|
|
143
|
-
**App:** {app_label}\n
|
|
144
|
-
**Table:** `{table_name}`\n
|
|
145
|
-
|
|
146
|
-
## Description
|
|
147
|
-
|
|
148
|
-
{description}
|
|
149
|
-
|
|
150
|
-
"""
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
def _add_fields_section(model_info: dict[str, Any]) -> str:
|
|
154
|
-
"""Add the fields section to the model documentation."""
|
|
155
|
-
fields = model_info.get("fields", {})
|
|
156
|
-
non_relationship_fields = {
|
|
157
|
-
name: info
|
|
158
|
-
for name, info in fields.items()
|
|
159
|
-
if info.get("type", "") not in ["ForeignKey", "OneToOneField", "ManyToManyField"]
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if not non_relationship_fields:
|
|
163
|
-
return ""
|
|
164
|
-
|
|
165
|
-
content = render_fields_table(non_relationship_fields)
|
|
166
|
-
content += "\n"
|
|
167
|
-
content += render_choices_tables(non_relationship_fields)
|
|
168
|
-
content += "\n"
|
|
169
|
-
return content
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def _add_relationships_section(model_info: dict[str, Any]) -> str:
|
|
173
|
-
"""Add the relationships section to the model documentation."""
|
|
174
|
-
fields = model_info.get("fields", {})
|
|
175
|
-
relationships = model_info.get("relationships", {})
|
|
176
|
-
|
|
177
|
-
relationship_fields = {
|
|
178
|
-
name: info
|
|
179
|
-
for name, info in fields.items()
|
|
180
|
-
if info.get("type", "") in ["ForeignKey", "OneToOneField", "ManyToManyField"]
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
if not (relationships or relationship_fields):
|
|
184
|
-
return ""
|
|
185
|
-
|
|
186
|
-
content = "## Relationships\n\n"
|
|
187
|
-
content += "| Field | Type | Related Model |\n"
|
|
188
|
-
content += "|-------|------|---------------|\n"
|
|
189
|
-
|
|
190
|
-
content += _render_relationship_fields(relationship_fields)
|
|
191
|
-
content += _render_relationships_from_section(relationships)
|
|
192
|
-
content += "\n"
|
|
193
|
-
|
|
194
|
-
return content
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
def _render_relationship_fields(relationship_fields: dict[str, Any]) -> str:
|
|
198
|
-
"""Render relationship fields from the fields section."""
|
|
199
|
-
content = ""
|
|
200
|
-
for field_name, field_info in relationship_fields.items():
|
|
201
|
-
field_type = field_info.get("type", "Unknown")
|
|
202
|
-
field_specific = field_info.get("field_specific", {})
|
|
203
|
-
to_model = field_specific.get("to", "")
|
|
204
|
-
|
|
205
|
-
if to_model:
|
|
206
|
-
model_link = _create_model_link(to_model)
|
|
207
|
-
content += f"| `{field_name}` | {field_type} | {model_link}|\n"
|
|
208
|
-
|
|
209
|
-
return content
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
def _render_relationships_from_section(relationships: dict[str, Any]) -> str:
|
|
213
|
-
"""Render relationships from the relationships section."""
|
|
214
|
-
content = ""
|
|
215
|
-
for rel_name, rel_info in relationships.items():
|
|
216
|
-
rel_type = rel_info.get("type", "Unknown")
|
|
217
|
-
related_model_full = rel_info.get("related_model", "")
|
|
218
|
-
|
|
219
|
-
if related_model_full and "." in related_model_full:
|
|
220
|
-
related_app, related_model = related_model_full.split(".", 1)
|
|
221
|
-
model_link = f"[{related_model}](../../{related_app}/{related_model.lower()}/)"
|
|
222
|
-
else:
|
|
223
|
-
model_link = related_model_full
|
|
224
|
-
|
|
225
|
-
content += f"| `{rel_name}` | {rel_type} | {model_link} | \n"
|
|
226
|
-
|
|
227
|
-
return content
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
def _create_model_link(to_model: str) -> str:
|
|
231
|
-
"""Create a link to a related model."""
|
|
232
|
-
if "." in to_model:
|
|
233
|
-
related_app, related_model = to_model.split(".", 1)
|
|
234
|
-
return f"[{related_model}](../{related_app}/{related_model.lower()}/)"
|
|
235
|
-
return f"[{to_model}]({to_model.lower()}/)"
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
def _add_methods_section(model_info: dict[str, Any]) -> str:
|
|
239
|
-
"""Add the methods section to the model documentation."""
|
|
240
|
-
methods = model_info.get("methods", [])
|
|
241
|
-
if not methods:
|
|
242
|
-
return ""
|
|
243
|
-
|
|
244
|
-
content = "## Methods\n\n"
|
|
245
|
-
for method in methods:
|
|
246
|
-
method_name = method.get("name", "")
|
|
247
|
-
docstring = method.get("docstring", "")
|
|
248
|
-
|
|
249
|
-
content += f"### `{method_name}()`\n\n"
|
|
250
|
-
if docstring:
|
|
251
|
-
content += f"{docstring}\n\n"
|
|
252
|
-
else:
|
|
253
|
-
content += "No documentation available.\n\n"
|
|
254
|
-
|
|
255
|
-
return content
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
def _add_meta_options_section(model_info: dict[str, Any]) -> str:
|
|
259
|
-
"""Add the meta options section to the model documentation."""
|
|
260
|
-
meta_options = model_info.get("meta_options", {})
|
|
261
|
-
if not meta_options:
|
|
262
|
-
return ""
|
|
263
|
-
|
|
264
|
-
content = "## Meta Options\n\n"
|
|
265
|
-
for option, value in meta_options.items():
|
|
266
|
-
content += f"- **{option}:** {value}\n"
|
|
267
|
-
content += "\n"
|
|
268
|
-
|
|
269
|
-
return content
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
from drf_to_mkdoc.utils.common import get_app_descriptions, get_model_description, write_file
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def create_models_index(models_data: dict[str, Any], docs_dir: Path) -> None:
|
|
8
|
+
models_by_app = {}
|
|
9
|
+
for model_name, model_info in models_data.items():
|
|
10
|
+
app_name = model_info.get("app_label", model_name.split(".")[0])
|
|
11
|
+
class_name = model_info.get("name", model_name.split(".")[-1])
|
|
12
|
+
if app_name not in models_by_app:
|
|
13
|
+
models_by_app[app_name] = []
|
|
14
|
+
models_by_app[app_name].append((class_name, model_name, model_info))
|
|
15
|
+
|
|
16
|
+
content = """# Django Models\n\nThis section contains documentation for
|
|
17
|
+
all Django models in the system, organized by Django application.\n\n"""
|
|
18
|
+
|
|
19
|
+
app_descriptions = get_app_descriptions()
|
|
20
|
+
|
|
21
|
+
for app_name in sorted(models_by_app.keys()):
|
|
22
|
+
app_desc = app_descriptions.get(app_name, f"{app_name.title()} application models")
|
|
23
|
+
content += f'<div class="app-header">{app_name.title()} App</div>\n\n'
|
|
24
|
+
content += f"*{app_desc}*\n\n"
|
|
25
|
+
|
|
26
|
+
content += '<div class="model-cards">\n'
|
|
27
|
+
|
|
28
|
+
for class_name, _model_name, _model_info in sorted(models_by_app[app_name]):
|
|
29
|
+
content += f"""
|
|
30
|
+
<a href="{app_name}/{class_name.lower()}/"
|
|
31
|
+
class="model-card">{class_name}</a>\n
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
content += "</div>\n\n"
|
|
35
|
+
|
|
36
|
+
content += """## Model Relationships\n\nThe models are interconnected through foreign keys
|
|
37
|
+
and many-to-many relationships:\n\n- **Users** can be associated
|
|
38
|
+
with multiple **Clinics** through **ClinicUser**
|
|
39
|
+
\n- **Doctors** belong to **Clinics**
|
|
40
|
+
and offer **Services** through **DoctorService**
|
|
41
|
+
\n- **Appointments** connect **Patients**
|
|
42
|
+
with **Doctors** and **Services**
|
|
43
|
+
\n- **Schedules** define **Doctor** availability in specific **Rooms**
|
|
44
|
+
\n- **Rooms** belong to **Clinics** and host **Appointments**\n
|
|
45
|
+
\nEach model page contains detailed field documentation,
|
|
46
|
+
method signatures, and relationships to other models.\n"""
|
|
47
|
+
|
|
48
|
+
models_index_path = docs_dir / "models" / "index.md"
|
|
49
|
+
models_index_path.parent.mkdir(parents=True, exist_ok=True)
|
|
50
|
+
|
|
51
|
+
with models_index_path.open("w", encoding="utf-8") as f:
|
|
52
|
+
f.write(content)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def generate_model_docs(models_data: dict[str, Any]) -> None:
|
|
56
|
+
"""Generate model documentation from JSON data"""
|
|
57
|
+
for model_name, model_info in models_data.items():
|
|
58
|
+
app_name = model_info.get("app_label", model_name.split(".")[0])
|
|
59
|
+
class_name = model_info.get("name", model_name.split(".")[-1])
|
|
60
|
+
|
|
61
|
+
# Create the model page content
|
|
62
|
+
content = create_model_page(model_info)
|
|
63
|
+
|
|
64
|
+
# Write the file in app subdirectory
|
|
65
|
+
file_path = f"models/{app_name}/{class_name.lower()}.md"
|
|
66
|
+
write_file(file_path, content)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def render_fields_table(fields: dict[str, Any]) -> str:
|
|
70
|
+
content = "## Fields\n\n"
|
|
71
|
+
content += "| Field | Type | Description | Extra |\n"
|
|
72
|
+
content += "|-------|------|-------------|-------|\n"
|
|
73
|
+
|
|
74
|
+
for field_name, field_info in fields.items():
|
|
75
|
+
field_type = field_info.get("type", "Unknown")
|
|
76
|
+
verbose_name = field_info.get("verbose_name", field_name)
|
|
77
|
+
help_text = field_info.get("help_text", "")
|
|
78
|
+
|
|
79
|
+
extra_info = []
|
|
80
|
+
if field_info.get("null"):
|
|
81
|
+
extra_info.append("null=True")
|
|
82
|
+
if field_info.get("blank"):
|
|
83
|
+
extra_info.append("blank=True")
|
|
84
|
+
if field_info.get("unique"):
|
|
85
|
+
extra_info.append("unique=True")
|
|
86
|
+
if field_info.get("primary_key"):
|
|
87
|
+
extra_info.append("primary_key=True")
|
|
88
|
+
if field_info.get("default"):
|
|
89
|
+
extra_info.append(f"default={field_info['default']}")
|
|
90
|
+
|
|
91
|
+
field_specific = field_info.get("field_specific", {})
|
|
92
|
+
for key, value in field_specific.items():
|
|
93
|
+
if key not in ["related_name", "related_query_name", "to"]:
|
|
94
|
+
extra_info.append(f"{key}={value}")
|
|
95
|
+
|
|
96
|
+
extra_str = ", ".join(extra_info) if extra_info else ""
|
|
97
|
+
description_str = help_text or verbose_name
|
|
98
|
+
|
|
99
|
+
content += f"| `{field_name}` | {field_type} | {description_str} | {extra_str} |\n"
|
|
100
|
+
|
|
101
|
+
return content
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def render_choices_tables(fields: dict[str, Any]) -> str:
|
|
105
|
+
choice_tables = []
|
|
106
|
+
|
|
107
|
+
for field_name, field_info in fields.items():
|
|
108
|
+
choices = field_info.get("choices")
|
|
109
|
+
if choices:
|
|
110
|
+
table = f"### {field_name} Choices\n\n"
|
|
111
|
+
table += "| Label | Value |\n"
|
|
112
|
+
table += "|-------|--------|\n"
|
|
113
|
+
for choice in choices:
|
|
114
|
+
table += f"| {choice['display']} | `{choice['value']}` |\n"
|
|
115
|
+
table += "\n"
|
|
116
|
+
choice_tables.append(table)
|
|
117
|
+
|
|
118
|
+
if choice_tables:
|
|
119
|
+
return "## Choices\n\n" + "\n".join(choice_tables)
|
|
120
|
+
return ""
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def create_model_page(model_info: dict[str, Any]) -> str:
|
|
124
|
+
"""Create a model documentation page from model info"""
|
|
125
|
+
name = model_info.get("name", "Unknown")
|
|
126
|
+
app_label = model_info.get("app_label", "unknown")
|
|
127
|
+
table_name = model_info.get("table_name", "")
|
|
128
|
+
description = get_model_description(name)
|
|
129
|
+
|
|
130
|
+
content = _create_model_header(name, app_label, table_name, description)
|
|
131
|
+
content += _add_fields_section(model_info)
|
|
132
|
+
content += _add_relationships_section(model_info)
|
|
133
|
+
content += _add_methods_section(model_info)
|
|
134
|
+
content += _add_meta_options_section(model_info)
|
|
135
|
+
|
|
136
|
+
return content
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _create_model_header(name: str, app_label: str, table_name: str, description: str) -> str:
|
|
140
|
+
"""Create the header section of the model documentation."""
|
|
141
|
+
return f"""# {name}
|
|
142
|
+
|
|
143
|
+
**App:** {app_label}\n
|
|
144
|
+
**Table:** `{table_name}`\n
|
|
145
|
+
|
|
146
|
+
## Description
|
|
147
|
+
|
|
148
|
+
{description}
|
|
149
|
+
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _add_fields_section(model_info: dict[str, Any]) -> str:
|
|
154
|
+
"""Add the fields section to the model documentation."""
|
|
155
|
+
fields = model_info.get("fields", {})
|
|
156
|
+
non_relationship_fields = {
|
|
157
|
+
name: info
|
|
158
|
+
for name, info in fields.items()
|
|
159
|
+
if info.get("type", "") not in ["ForeignKey", "OneToOneField", "ManyToManyField"]
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if not non_relationship_fields:
|
|
163
|
+
return ""
|
|
164
|
+
|
|
165
|
+
content = render_fields_table(non_relationship_fields)
|
|
166
|
+
content += "\n"
|
|
167
|
+
content += render_choices_tables(non_relationship_fields)
|
|
168
|
+
content += "\n"
|
|
169
|
+
return content
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _add_relationships_section(model_info: dict[str, Any]) -> str:
|
|
173
|
+
"""Add the relationships section to the model documentation."""
|
|
174
|
+
fields = model_info.get("fields", {})
|
|
175
|
+
relationships = model_info.get("relationships", {})
|
|
176
|
+
|
|
177
|
+
relationship_fields = {
|
|
178
|
+
name: info
|
|
179
|
+
for name, info in fields.items()
|
|
180
|
+
if info.get("type", "") in ["ForeignKey", "OneToOneField", "ManyToManyField"]
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if not (relationships or relationship_fields):
|
|
184
|
+
return ""
|
|
185
|
+
|
|
186
|
+
content = "## Relationships\n\n"
|
|
187
|
+
content += "| Field | Type | Related Model |\n"
|
|
188
|
+
content += "|-------|------|---------------|\n"
|
|
189
|
+
|
|
190
|
+
content += _render_relationship_fields(relationship_fields)
|
|
191
|
+
content += _render_relationships_from_section(relationships)
|
|
192
|
+
content += "\n"
|
|
193
|
+
|
|
194
|
+
return content
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _render_relationship_fields(relationship_fields: dict[str, Any]) -> str:
|
|
198
|
+
"""Render relationship fields from the fields section."""
|
|
199
|
+
content = ""
|
|
200
|
+
for field_name, field_info in relationship_fields.items():
|
|
201
|
+
field_type = field_info.get("type", "Unknown")
|
|
202
|
+
field_specific = field_info.get("field_specific", {})
|
|
203
|
+
to_model = field_specific.get("to", "")
|
|
204
|
+
|
|
205
|
+
if to_model:
|
|
206
|
+
model_link = _create_model_link(to_model)
|
|
207
|
+
content += f"| `{field_name}` | {field_type} | {model_link}|\n"
|
|
208
|
+
|
|
209
|
+
return content
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _render_relationships_from_section(relationships: dict[str, Any]) -> str:
|
|
213
|
+
"""Render relationships from the relationships section."""
|
|
214
|
+
content = ""
|
|
215
|
+
for rel_name, rel_info in relationships.items():
|
|
216
|
+
rel_type = rel_info.get("type", "Unknown")
|
|
217
|
+
related_model_full = rel_info.get("related_model", "")
|
|
218
|
+
|
|
219
|
+
if related_model_full and "." in related_model_full:
|
|
220
|
+
related_app, related_model = related_model_full.split(".", 1)
|
|
221
|
+
model_link = f"[{related_model}](../../{related_app}/{related_model.lower()}/)"
|
|
222
|
+
else:
|
|
223
|
+
model_link = related_model_full
|
|
224
|
+
|
|
225
|
+
content += f"| `{rel_name}` | {rel_type} | {model_link} | \n"
|
|
226
|
+
|
|
227
|
+
return content
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def _create_model_link(to_model: str) -> str:
|
|
231
|
+
"""Create a link to a related model."""
|
|
232
|
+
if "." in to_model:
|
|
233
|
+
related_app, related_model = to_model.split(".", 1)
|
|
234
|
+
return f"[{related_model}](../{related_app}/{related_model.lower()}/)"
|
|
235
|
+
return f"[{to_model}]({to_model.lower()}/)"
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _add_methods_section(model_info: dict[str, Any]) -> str:
|
|
239
|
+
"""Add the methods section to the model documentation."""
|
|
240
|
+
methods = model_info.get("methods", [])
|
|
241
|
+
if not methods:
|
|
242
|
+
return ""
|
|
243
|
+
|
|
244
|
+
content = "## Methods\n\n"
|
|
245
|
+
for method in methods:
|
|
246
|
+
method_name = method.get("name", "")
|
|
247
|
+
docstring = method.get("docstring", "")
|
|
248
|
+
|
|
249
|
+
content += f"### `{method_name}()`\n\n"
|
|
250
|
+
if docstring:
|
|
251
|
+
content += f"{docstring}\n\n"
|
|
252
|
+
else:
|
|
253
|
+
content += "No documentation available.\n\n"
|
|
254
|
+
|
|
255
|
+
return content
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def _add_meta_options_section(model_info: dict[str, Any]) -> str:
|
|
259
|
+
"""Add the meta options section to the model documentation."""
|
|
260
|
+
meta_options = model_info.get("meta_options", {})
|
|
261
|
+
if not meta_options:
|
|
262
|
+
return ""
|
|
263
|
+
|
|
264
|
+
content = "## Meta Options\n\n"
|
|
265
|
+
for option, value in meta_options.items():
|
|
266
|
+
content += f"- **{option}:** {value}\n"
|
|
267
|
+
content += "\n"
|
|
268
|
+
|
|
269
|
+
return content
|