reqparser.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. from abc import ABC, abstractmethod
  2. from dataclasses import dataclass
  3. from typing import ClassVar, Dict
  4. from flask import g, request
  5. from pydantic import BaseModel
  6. from werkzeug.datastructures import ImmutableMultiDict
  7. from werkzeug.exceptions import BadRequest,UnsupportedMediaType
  8. from ruoyi_common.base.model import BaseEntity, CriterianMeta, ExtraModel, \
  9. BaseEntity, OrderModel, PageModel, VoValidatorContext
  10. from ruoyi_common.base.schema_vo import BaseSchemaFactory, QuerySchemaFactory
  11. class AbsReqParser(ABC):
  12. @abstractmethod
  13. def data(self) -> Dict:
  14. """
  15. 获取请求参数
  16. Returns:
  17. Dict: 请求参数字典
  18. """
  19. @abstractmethod
  20. def cast_model(self, bo_model:BaseEntity) -> BaseModel:
  21. """
  22. 适配模型
  23. Args:
  24. bo_model (BaseEntity): Vo模型
  25. src_model (BaseModel): 源模型
  26. Returns:
  27. BaseModel: 适配后的模型
  28. """
  29. @abstractmethod
  30. def prepare_factory(self, factory:BaseSchemaFactory):
  31. """
  32. 准备工厂
  33. Args:
  34. factory (BaseSchemaFactory): 工厂
  35. """
  36. @abstractmethod
  37. def prepare(self):
  38. """
  39. 准备数据
  40. """
  41. class BaseReqParser(AbsReqParser):
  42. def data(self) -> Dict:
  43. pass
  44. def cast_model(self, bo_model:BaseEntity) -> BaseModel:
  45. pass
  46. def prepare_factory(self, factory:BaseSchemaFactory):
  47. pass
  48. def prepare(self):
  49. pass
  50. class QueryReqParser(BaseReqParser):
  51. def __init__(self, context:VoValidatorContext):
  52. self.context = context
  53. self.extra_model = ExtraModel
  54. def prepare_factory(self, factory: QuerySchemaFactory):
  55. if factory.extra_model:
  56. self.extra_model = factory.extra_model
  57. def prepare(self):
  58. self.criterian_meta = CriterianMeta()
  59. g.criterian_meta = self.criterian_meta
  60. def validate_request(self) -> Dict:
  61. return request.args.to_dict()
  62. def data(self) -> Dict:
  63. data = self.validate_request().copy()
  64. if self.context.is_page:
  65. page = PageModel.model_validate(data,context=self.context)
  66. if page.model_fields_set:
  67. self.criterian_meta.page = page
  68. if self.context.is_sort:
  69. sort = OrderModel.model_validate(data,context=self.context)
  70. if sort.model_fields_set:
  71. self.criterian_meta.sort = sort
  72. if self.extra_model:
  73. extra = self.extra_model.model_validate(data,context=self.context)
  74. if extra.model_fields_set:
  75. self.criterian_meta.extra = extra
  76. return data
  77. def cast_model(self, bo_model:BaseEntity) -> BaseModel:
  78. data = self.data()
  79. bo = bo_model.model_validate(data)
  80. return bo
  81. @dataclass
  82. class PathReqParser(BaseReqParser):
  83. def data(self) -> Dict:
  84. return request.view_args.copy()
  85. @dataclass
  86. class BodyReqParser(BaseReqParser):
  87. minetype: ClassVar[str] = "application/json"
  88. def __init__(self, context:VoValidatorContext):
  89. self.context = context
  90. def validate_request(self) -> Dict:
  91. content_type = request.headers.get("Content-Type", "").lower()
  92. minetype = content_type.split(";")[0]
  93. if minetype == self.minetype:
  94. body: dict | list = request.get_json()
  95. if not body:
  96. raise BadRequest(
  97. description="在{}, body数据不能为空".format(content_type),
  98. )
  99. else:
  100. raise UnsupportedMediaType(
  101. description="content-type仅支持application/json"
  102. )
  103. return body
  104. def data(self) -> Dict:
  105. data = self.validate_request().copy()
  106. return data
  107. def cast_model(self, bo_model:BaseEntity) -> BaseModel:
  108. data = self.data()
  109. bo = bo_model.model_validate(data, context=self.context)
  110. return bo
  111. @dataclass
  112. class FormUrlencodedQueryReqParser(QueryReqParser):
  113. minetype: ClassVar[str] = "application/x-www-form-urlencoded"
  114. def __init__(self, context:VoValidatorContext):
  115. super().__init__(context)
  116. def validate_request(self) -> Dict:
  117. content_type = request.headers.get("Content-Type", "").lower()
  118. minetype = content_type.split(";")[0]
  119. if minetype == self.minetype:
  120. form:ImmutableMultiDict = request.form
  121. body = form.to_dict()
  122. else:
  123. raise UnsupportedMediaType(
  124. description="除了{},content-type不支持{}".format(self.minetype,minetype)
  125. )
  126. return body
  127. @dataclass
  128. class DownloadFileQueryReqParser(FormUrlencodedQueryReqParser):
  129. def __init__(self, context:VoValidatorContext):
  130. super().__init__(context)
  131. class FormReqParser(BaseReqParser):
  132. minetype: ClassVar[str] = "multipart/form-data"
  133. def __init__(
  134. self,
  135. is_form:bool=True,
  136. is_query:bool=False,
  137. is_file:bool|None=None,
  138. ):
  139. self.is_form = is_form
  140. self.is_query = is_query
  141. self.is_file = is_file
  142. def validate_request(self) -> Dict:
  143. content_type = request.headers.get("Content-Type", "").lower()
  144. minetype = content_type.split(";")[0]
  145. new_data = {}
  146. if minetype == self.minetype:
  147. if self.is_form:
  148. new_data.update(request.form.to_dict())
  149. if self.is_query:
  150. new_data.update(request.args.to_dict())
  151. if self.is_file:
  152. new_data.update(request.files.to_dict(flat=False))
  153. else:
  154. raise UnsupportedMediaType(
  155. description="除了{},content-type不支持{}".format(self.minetype,minetype)
  156. )
  157. return new_data
  158. def data(self) -> Dict:
  159. data = self.validate_request()
  160. return data
  161. class UploadFileFormReqParser(FormReqParser):
  162. def validate_request(self) -> Dict:
  163. return super().validate_request()
  164. def data(self) -> Dict:
  165. data = self.validate_request()
  166. return data
  167. class StreamReqParser(BaseReqParser):
  168. minetype: ClassVar[str] = "application/octet-stream"
  169. def data(self, *args, **kwargs) -> Dict:
  170. pass