-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmain.py
159 lines (142 loc) · 5.35 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
import logging
from importlib import import_module
from typing import Any, Callable, Optional, Sequence, Union
from django.conf import settings
from django.http import HttpRequest, HttpResponse
from django.utils.module_loading import module_has_submodule
from ninja.constants import NOT_SET, NOT_SET_TYPE
from ninja.parser import Parser
from ninja.renderers import BaseRenderer
from ninja.types import TCallable
from ninja_extra import NinjaExtraAPI
from easy.controller.auto_api import create_admin_controller
from easy.domain.orm import django_serializer
from easy.renderer.json import EasyJSONRenderer
from easy.response import BaseAPIResponse
logger = logging.getLogger(__name__)
class EasyAPI(NinjaExtraAPI):
"""
EasyAPI, extensions:
-Add 2 init params
Easy_extra: bool = True,
Can serialize queryset or model, and support pagination
Easy_output: bool = True,
If True, will be encapsulated in BaseAPIResponse
-renderer, default to EasyJSONRenderer
-Auto generate AdminAPIs, it will read the following settings:
CRUD_API_ENABLED_ALL_APPS
CRUD_API_EXCLUDE_APPS
CRUD_API_INCLUDE_APPS
"""
def __init__(
self,
*,
title: str = "Easy API",
version: str = "1.0.0",
description: str = "",
openapi_url: Optional[str] = "/openapi.json",
docs_url: Optional[str] = "/docs",
docs_decorator: Optional[Callable[[TCallable], TCallable]] = None,
urls_namespace: Optional[str] = None,
csrf: bool = False,
auth: Union[
Sequence[Callable[..., Any]], Callable[..., Any], NOT_SET_TYPE, None
] = NOT_SET,
renderer: Optional[BaseRenderer] = EasyJSONRenderer(),
parser: Optional[Parser] = None,
app_name: str = "ninja",
easy_extra: bool = True,
easy_output: bool = True,
) -> None:
super(NinjaExtraAPI, self).__init__(
title=title,
version=version,
description=description,
openapi_url=openapi_url,
docs_url=docs_url,
docs_decorator=docs_decorator,
urls_namespace=urls_namespace,
csrf=csrf,
auth=auth,
renderer=renderer,
parser=parser,
)
self.docs_decorator = docs_decorator
self.app_name = app_name
self.easy_extra = easy_extra
self.easy_output = easy_output
def auto_create_admin_controllers(self, version: str = None) -> None:
for app_module in self.get_installed_apps():
# If not all
if not settings.CRUD_API_ENABLED_ALL_APPS: # type:ignore
# Only generate for this included apps
if settings.CRUD_API_INCLUDE_APPS is not None: # type:ignore
if (
app_module.name
not in settings.CRUD_API_INCLUDE_APPS # type:ignore
):
continue
# Exclude list
if app_module.name in settings.CRUD_API_EXCLUDE_APPS: # type:ignore
continue
try:
app_module_ = import_module(app_module.name)
final = []
if module_has_submodule(app_module_, "models"):
# Auto generate AdminAPI
for model in app_module.get_models():
final.append(
create_admin_controller(
model, app_module.name.split(".")[1]
)
)
self.register_controllers(*final)
except ImportError as ex: # pragma: no cover
raise ex
@staticmethod
def get_installed_apps() -> list:
from django.apps import apps
return [
v
for k, v in apps.app_configs.items()
if not v.name.startswith("django.") and (not v.name == "easy.api")
]
def create_response(
self,
request: HttpRequest,
data: Any,
*,
status: int = None,
temporal_response: HttpResponse = None,
) -> HttpResponse:
if self.easy_extra:
try:
data = django_serializer.serialize_data(data)
except Exception as e: # pragma: no cover
logger.error(f"Creat Response Error - {e}", exc_info=True)
return BaseAPIResponse(str(e), code=500)
if self.easy_output:
if temporal_response:
status = temporal_response.status_code
assert status
_temp = BaseAPIResponse(
data, status=status, content_type=self.get_content_type()
)
if temporal_response:
response = temporal_response
response.content = _temp.content
else:
response = _temp
else:
response = super().create_response(
request,
data,
status=status,
temporal_response=temporal_response,
)
return response
def create_temporal_response(self, request: HttpRequest) -> HttpResponse:
if self.easy_output:
return BaseAPIResponse("", content_type=self.get_content_type())
else:
return super().create_temporal_response(request)