Skip to content

Commit 1923de5

Browse files
committed
feat: Many to many 필드에 대한 대응 추가
1 parent 328f77c commit 1923de5

File tree

1 file changed

+32
-29
lines changed

1 file changed

+32
-29
lines changed

app/core/viewset/json_schema_viewset.py

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
from __future__ import annotations
22

3+
import functools
34
import typing
45

56
from core.const.tag import OpenAPITag
67
from core.serializer.json_schema_serializer import JsonSchemaSerializer
8+
from django.db.models.base import Model
79
from django.db.models.fields.files import FileField
8-
from django.db.models.fields.related import ForeignKey
10+
from django.db.models.fields.related import ForeignKey, ManyToManyField
911
from drf_spectacular import openapi, types, utils
1012
from modeltranslation.fields import TranslationField
1113
from rest_framework import decorators, response, status, viewsets
@@ -18,6 +20,23 @@ def __new__(cls, *args: tuple, **kwargs: dict) -> JsonSchemaViewSet:
1820

1921
return super().__new__(cls)
2022

23+
@staticmethod
24+
@functools.lru_cache
25+
def get_enum_values(model: Model, is_nullable: bool) -> list[dict[str, str]]:
26+
enum_values: list[dict[str, str]] = [{"const": None, "title": "빈 값"}] if is_nullable else []
27+
28+
if hasattr(model, "objects"):
29+
qs = model.objects.all()
30+
if hasattr(qs, "filter_active"):
31+
qs = qs.filter_active()
32+
elif hasattr(model, "is_active"):
33+
qs = qs.filter(is_active=True)
34+
35+
for row in list(qs):
36+
enum_values.append({"const": str(row.pk), "title": str(row)})
37+
38+
return enum_values
39+
2140
def get_json_schema(self) -> dict:
2241
serializer_class = typing.cast(type[JsonSchemaSerializer], self.get_serializer_class())
2342

@@ -27,38 +46,22 @@ def get_json_schema(self) -> dict:
2746
"translation_fields": set(),
2847
}
2948

30-
nullable_fields = [
31-
k for k, v in serializer_class.get_json_schema()["properties"].items() if "null" in v.get("type", [])
32-
]
33-
3449
if hasattr(serializer_class.Meta, "model") and "properties" in result["schema"]:
3550
model_fields = serializer_class.Meta.model._meta.fields
51+
model_m2m_fields = serializer_class.Meta.model._meta.many_to_many
3652

37-
for field in model_fields:
38-
if isinstance(field, ForeignKey):
39-
enum_values = []
40-
row_qs = field.related_model.objects
41-
if hasattr(row_qs, "filter_active"):
42-
row_qs = row_qs.filter_active()
43-
elif hasattr(field.related_model, "is_active"):
44-
row_qs = row_qs.filter(is_active=True)
45-
46-
for row in row_qs:
47-
enum_values.append({"id": row.pk, "name": str(row)})
48-
49-
if field.name in result["schema"]["properties"]:
50-
result["schema"]["properties"][field.name]["enum"] = [e["id"] for e in enum_values] + (
51-
[None] if field.null else []
52-
)
53-
54-
result["ui_schema"][field.name] = {
55-
"ui:options": {
56-
"ui:widget": "select",
57-
"enumNames": [f"{e['name']} <{e['id']}>" for e in enum_values]
58-
+ (["빈 값"] if field.name in nullable_fields else []),
59-
}
60-
}
53+
for field in model_fields + model_m2m_fields:
54+
if field.name not in result["schema"]["properties"]:
55+
continue
6156

57+
if isinstance(field, ForeignKey):
58+
e_values = self.get_enum_values(field.related_model, field.null)
59+
result["schema"]["properties"][field.name]["oneOf"] = e_values
60+
elif isinstance(field, ManyToManyField):
61+
e_values = self.get_enum_values(field.related_model, False)
62+
result["schema"]["properties"][field.name]["items"]["oneOf"] = e_values
63+
result["schema"]["properties"][field.name]["uniqueItems"] = True
64+
result["ui_schema"][field.name] = {"ui:field": "m2m_select"}
6265
elif isinstance(field, FileField):
6366
result["ui_schema"][field.name] = {"ui:field": "file"}
6467
elif isinstance(field, TranslationField):

0 commit comments

Comments
 (0)