11import json
22import logging
3+ import re
34import uuid
45from abc import ABCMeta
5- from typing import Any , List , Optional , Tuple , Type , Union
6+ from collections import ChainMap
7+ from typing import Any , List , Match , Optional , Tuple , Type , Union
68
79from django .db import models
810from django .http import HttpRequest
@@ -27,16 +29,29 @@ class APIControllerBase(ControllerBase):
2729class CrudAPI (CrudModel ):
2830 # Never add type note to service, it will cause injection error
2931 def __init__ (self , service = None ): # type: ignore
32+ # Critical to set __Meta
33+ self .service = service
34+ if self .service :
35+ self .model = self .service .model
36+ _meta = getattr (self , "Meta" , None )
37+ if self .model and _meta :
38+ setattr (
39+ self .model ,
40+ "__Meta" ,
41+ {
42+ "model_exclude" : getattr (_meta , "model_exclude" , None ),
43+ "model_fields" : getattr (_meta , "model_fields" , "__all__" ),
44+ "model_recursive" : getattr (_meta , "model_recursive" , False ),
45+ "model_join" : getattr (_meta , "model_join" , True ),
46+ "sensitive_fields" : getattr (
47+ _meta , "model_sensitive_fields" , ["password" , "token" ]
48+ ),
49+ },
50+ )
3051 if not service :
3152 self .service = BaseService (model = self .model )
32- else :
33- self .service = service
3453 super ().__init__ (model = self .model )
3554
36- # Critical to set Meta
37- if hasattr (self , "Meta" ):
38- self .model .Meta = self .Meta # type: ignore
39-
4055 # Define Controller APIs for auto generation
4156 async def get_obj (self , request : HttpRequest , id : int ) -> Any :
4257 """
@@ -73,28 +88,11 @@ async def get_objs(self, request: HttpRequest, filters: str = None) -> Any:
7388 return await self .service .get_objs (** json .loads (filters ))
7489 return await self .service .get_objs ()
7590
76- # async def bulk_create_objs(self, request):
77- # """
78- # POST /bulk_create
79- # Create multiple Object
80- # """
81- # return await self.service.bulk_create_objs()
82- #
83- # async def recover_obj(self, request):
84- # """
85- # PATCH /{id}/recover
86- # Recover one Object
87- # """
88- # return await self.service.recover_obj()
89- #
90-
9191
9292class CrudApiMetaclass (ABCMeta ):
9393 def __new__ (mcs , name : str , bases : Tuple [Type [Any ], ...], attrs : dict ) -> Any :
9494 # Get configs from Meta
95- temp_cls : Type = super (CrudApiMetaclass , mcs ).__new__ (
96- mcs , name , (object ,), attrs
97- )
95+ temp_cls : Type = super ().__new__ (mcs , name , (object ,), attrs )
9896 temp_opts : ModelOptions = ModelOptions (getattr (temp_cls , "Meta" , None ))
9997 opts_model : Optional [Type [models .Model ]] = temp_opts .model
10098 opts_fields_exclude : Optional [str ] = temp_opts .model_exclude
@@ -105,17 +103,18 @@ def __new__(mcs, name: str, bases: Tuple[Type[Any], ...], attrs: dict) -> Any:
105103 Union [str , List [str ]]
106104 ] = temp_opts .sensitive_fields
107105
108- base_cls_attrs = {
109- "get_obj" : http_get ("/{id}" , summary = "Get a single object" )(
110- copy_func (CrudAPI .get_obj ) # type: ignore
111- ),
112- "del_obj" : http_delete ("/{id}" , summary = "Delete a single object" )(
113- copy_func (CrudAPI .del_obj ) # type: ignore
114- ),
115- "get_all" : http_get ("/" , summary = "Get multiple objects" )(
116- copy_func (CrudAPI .get_objs ) # type: ignore
117- ),
118- }
106+ def is_private_attrs (attr_name : str ) -> Optional [Match [str ]]:
107+ return re .match (r"^__[^\d\W]\w*\Z__$" , attr_name , re .UNICODE )
108+
109+ parent_attrs = ChainMap (
110+ * [attrs ]
111+ + [
112+ {k : v for (k , v ) in vars (base ).items () if not (is_private_attrs (k ))}
113+ for base in bases
114+ ]
115+ )
116+ base_cls_attrs : dict = {}
117+ base_cls_attrs .update (parent_attrs )
119118
120119 if opts_model :
121120
@@ -159,35 +158,60 @@ async def patch_obj( # type: ignore
159158 f"{ opts_model .__name__ } __AutoSchema({ str (uuid .uuid4 ())[:4 ]} )"
160159 )
161160
162- setattr (CrudAPI , "add_obj " , classmethod ( add_obj ) )
163- setattr (CrudAPI , "patch_obj " , classmethod ( patch_obj ) )
161+ setattr (CrudAPI , "patch_obj " , patch_obj )
162+ setattr (CrudAPI , "add_obj " , add_obj )
164163
165164 base_cls_attrs .update (
166165 {
167- "patch_obj" : http_patch ("/{id}" , summary = "Patch a single object" )(
166+ "patch_obj_api" : http_patch (
167+ "/{id}" , summary = "Patch a single object"
168+ )(
168169 copy_func (CrudAPI .patch_obj ) # type: ignore
169170 ),
170- "add_obj " : http_put ("/" , summary = "Create" )(
171+ "add_obj_api " : http_put ("/" , summary = "Create" )(
171172 copy_func (CrudAPI .add_obj ) # type: ignore
172173 ),
173174 }
174175 )
175176
176- new_base : Type = type .__new__ (
177- type , name , (APIControllerBase , CrudAPI ), base_cls_attrs
177+ base_cls_attrs .update (
178+ {
179+ "get_obj_api" : http_get ("/{id}" , summary = "Get a single object" )(
180+ copy_func (CrudAPI .get_obj ) # type: ignore
181+ ),
182+ "del_obj_api" : http_delete ("/{id}" , summary = "Delete a single object" )(
183+ copy_func (CrudAPI .del_obj ) # type: ignore
184+ ),
185+ "get_objs_api" : http_get ("/" , summary = "Get multiple objects" )(
186+ copy_func (CrudAPI .get_objs ) # type: ignore
187+ ),
188+ }
178189 )
179- new_cls : Type = super (CrudApiMetaclass , mcs ).__new__ (
180- mcs , name , (new_base ,), attrs
190+
191+ new_cls : Type = super ().__new__ (
192+ mcs ,
193+ name ,
194+ (
195+ APIControllerBase ,
196+ CrudAPI ,
197+ ),
198+ base_cls_attrs ,
181199 )
182200
183201 if opts_model :
184- if hasattr (opts_model , "Meta" ):
185- setattr (opts_model .Meta , "model_exclude" , opts_fields_exclude )
186- setattr (opts_model .Meta , "model_fields" , opts_fields )
187- setattr (opts_model .Meta , "model_recursive" , opts_recursive )
188- setattr (opts_model .Meta , "model_join" , opts_join )
189- setattr (opts_model .Meta , "sensitive_fields" , opts_sensitive_fields )
202+ setattr (
203+ opts_model ,
204+ "__Meta" ,
205+ {
206+ "model_exclude" : opts_fields_exclude ,
207+ "model_fields" : opts_fields ,
208+ "model_recursive" : opts_recursive ,
209+ "model_join" : opts_join ,
210+ "sensitive_fields" : opts_sensitive_fields ,
211+ },
212+ )
190213 setattr (new_cls , "model" , opts_model )
214+
191215 return new_cls
192216
193217
0 commit comments