Skip to content

Commit f11ff3f

Browse files
committed
完成查询逻辑的设计
1 parent 5f23db4 commit f11ff3f

File tree

6 files changed

+104
-110
lines changed

6 files changed

+104
-110
lines changed

fast_tmp/admin/endpoint.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,4 +187,4 @@ async def get_schema(
187187
page: ModelAdmin = Depends(get_model_site),
188188
user: Optional[User] = Depends(__get_user),
189189
):
190-
return BaseRes(data=await page.get_app_page(request))
190+
return BaseRes(data=page.get_app_page(request))

fast_tmp/amis/crud.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from fast_tmp.amis.abstract_schema import BaseAmisModel, _Action
44
from fast_tmp.amis.buttons import Operation
55
from fast_tmp.amis.enums import TypeEnum
6+
from fast_tmp.amis.filter import FilterModel
67
from fast_tmp.amis.forms import Column
78

89

@@ -15,6 +16,7 @@ class CRUD(BaseAmisModel):
1516
affixHeader: bool = False
1617
quickSaveItemApi: Optional[str] # 快速保存
1718
syncLocation: Optional[bool]
19+
filter: Optional[FilterModel]
1820

1921
class Config:
2022
arbitrary_types_allowed = True

fast_tmp/amis/filter.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from typing import List, Optional
2+
3+
from pydantic import BaseModel
4+
5+
6+
class Filter(BaseModel):
7+
type: str
8+
name: str
9+
label: str
10+
clearable: Optional[bool]
11+
placeholder: Optional[str]
12+
13+
14+
class FilterModel(BaseModel):
15+
title: str = "条件搜索"
16+
body: List[Filter]
17+
actions: List[dict] = [
18+
{"type": "submit", "level": "primary", "label": "查询"}
19+
] # type submit label https://aisuda.bce.baidu.com/amis/zh-CN/components/crud#%E6%95%B0%E6%8D%AE%E6%BA%90%E6%8E%A5%E5%8F%A3%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E8%A6%81%E6%B1%82

fast_tmp/site/__init__.py

Lines changed: 61 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@
1212
from ..amis.actions import AjaxAction, DialogAction, DrawerAction
1313
from ..amis.buttons import Operation
1414
from ..amis.enums import ButtonLevelEnum
15+
from ..amis.filter import Filter, FilterModel
1516
from ..amis.forms import Form
1617
from ..amis.frame import Dialog, Drawer
18+
from .base import ModelFilter
1719
from .util import AbstractControl, BaseAdminControl, RelationSelectApi, create_column
1820

1921
logger = logging.getLogger(__file__)
@@ -55,8 +57,8 @@ class ModelAdmin(DbSession): # todo inline字段必须都在update_fields内
5557
inline: Tuple[str, ...] = ()
5658
prefix: str
5759
# search list
58-
search_fields: Tuple[str, ...] = ()
59-
filter_fields: Tuple[str, ...] = ()
60+
searchs: Tuple[str, ...] = ()
61+
filters: Tuple[ModelFilter, ...] = ()
6062
# create
6163
create_fields: Tuple[str, ...] = ()
6264
# exclude: Tuple[Union[str, BaseModel], ...] = ()
@@ -77,12 +79,29 @@ class ModelAdmin(DbSession): # todo inline字段必须都在update_fields内
7779
list_per_page: int = 10 # 每页多少数据
7880
list_max_show_all: int = 200 # 最多每页多少数据
7981
selct_defs = None
82+
_filters = None
8083

8184
def name(self) -> str:
8285
if self.__name is None:
8386
self.__name = self.model.__name__
8487
return self.__name
8588

89+
def get_filters(self):
90+
if not self._filters:
91+
self._filters = {i.name: i for i in self.filters}
92+
return self._filters
93+
94+
def queryset_filter(self, request: Request, queryset: QuerySet):
95+
query = request.query_params
96+
filter_fs = self.get_filters()
97+
for k, v in query.items():
98+
if k in ("pk", "page", "perPage"):
99+
continue
100+
func = filter_fs.get(k)
101+
if func is not None:
102+
queryset = func.queryset(request, queryset, v)
103+
return queryset
104+
86105
def get_create_fields(self) -> Dict[str, BaseAdminControl]:
87106
return {i: self.fields[i] for i in self.create_fields}
88107

@@ -94,7 +113,7 @@ def get_update_fields_with_pk(self) -> Dict[str, BaseAdminControl]:
94113
ret["pk"] = self.fields["pk"]
95114
return ret
96115

97-
async def get_create_dialogation_button(self, request: Request):
116+
def get_create_dialogation_button(self, request: Request):
98117
controls = self.get_create_fields()
99118

100119
return DialogAction(
@@ -110,7 +129,7 @@ async def get_create_dialogation_button(self, request: Request):
110129
),
111130
)
112131

113-
async def get_list_page(self, request: Request):
132+
def get_list_page(self, request: Request):
114133
res = []
115134
for field_name, col in self.get_list_distplay().items():
116135
if field_name in self.inline:
@@ -128,7 +147,7 @@ def get_del_one_button(self):
128147
api="delete:" + self.name() + "/delete/$pk",
129148
)
130149

131-
async def get_update_one_button(self, request: Request):
150+
def get_update_one_button(self, request: Request):
132151
body = [i.get_control(request) for i in self.get_update_fields().values()]
133152
return DialogAction(
134153
label="修改",
@@ -145,30 +164,48 @@ async def get_update_one_button(self, request: Request):
145164
),
146165
)
147166

148-
async def get_operation(self, request: Request):
167+
def get_operation(self, request: Request):
149168
buttons = []
150169
if "put" in self.methods and self.update_fields:
151-
buttons.append(await self.get_update_one_button(request))
170+
buttons.append(self.get_update_one_button(request))
152171
if "delete" in self.methods:
153172
buttons.append(self.get_del_one_button())
154173
return Operation(buttons=buttons)
155174

156-
async def get_crud(self, request: Request):
175+
def get_filter_page(self, request: Request):
176+
"""
177+
页面上的过滤框
178+
"""
179+
return FilterModel(
180+
body=[
181+
Filter(
182+
type=v.type,
183+
name=v.name,
184+
label=v.label,
185+
clearable=v.clearable,
186+
placeholder=v.placeholder,
187+
)
188+
for v in self.get_filters().values()
189+
]
190+
)
191+
192+
def get_crud(self, request: Request):
157193
body = []
158194
columns = []
159195
if "create" in self.methods and self.create_fields:
160-
body.append(await self.get_create_dialogation_button(request))
196+
body.append(self.get_create_dialogation_button(request))
161197
if "list" in self.methods and self.list_display:
162-
columns.extend(await self.get_list_page(request))
163-
columns.append(await self.get_operation(request))
164-
body.append(
165-
CRUD(
166-
api=self.prefix + "/list",
167-
columns=columns,
168-
quickSaveItemApi=self.prefix + "/patch/" + "$pk",
169-
syncLocation=False,
170-
)
198+
columns.extend(self.get_list_page(request))
199+
columns.append(self.get_operation(request))
200+
crud = CRUD(
201+
api=self.prefix + "/list",
202+
columns=columns,
203+
quickSaveItemApi=self.prefix + "/patch/" + "$pk",
204+
syncLocation=False,
171205
)
206+
if len(self.get_filters()) > 0:
207+
crud.filter = self.get_filter_page(request)
208+
body.append(crud)
172209
return body
173210

174211
def get_list_distplay(self) -> Dict[str, BaseAdminControl]:
@@ -182,8 +219,8 @@ def get_list_display_with_pk(self) -> Dict[str, BaseAdminControl]:
182219
ret["pk"] = self.fields["pk"]
183220
return ret
184221

185-
async def get_app_page(self, request: Request):
186-
return Page(title=self.name(), body=await self.get_crud(request)).dict(exclude_none=True)
222+
def get_app_page(self, request: Request):
223+
return Page(title=self.name(), body=self.get_crud(request)).dict(exclude_none=True)
187224

188225
async def put(self, request: Request, pk: str, data: Dict[str, Any]) -> Model:
189226
obj = await self.get_instance(request, pk)
@@ -228,87 +265,6 @@ def prefetch(
228265
queryset = field.prefetch(request, queryset)
229266
return queryset
230267

231-
# @classmethod
232-
# def create_model(cls, data: dict, session: Session):
233-
# """
234-
# 写入数据库之前调用
235-
# """
236-
# instance = cls.model()
237-
# for k, v in data.items():
238-
# field = getattr(cls.model, k)
239-
# if isinstance(field.property, RelationshipProperty):
240-
# if field.property.direction == MANYTOMANY:
241-
# model = field.mapper.class_
242-
# pk = list(get_pk(model).values())[0]
243-
# childs = session.execute(select(model).where(pk.in_(v))).scalars().fetchall()
244-
# setattr(instance, k, childs)
245-
# # getattr(instance, k).append(*childs)
246-
# elif field.property.direction == MANYTOONE:
247-
# field = get_real_column_field(field)
248-
# setattr(instance, field.key, v)
249-
# elif field.property.direction == ONETOMANY: # todo 暂时不考虑支持
250-
# # onetoone
251-
# if not getattr(field.property, "uselist"):
252-
# pass
253-
# else:
254-
# pass
255-
# else:
256-
# raise AttributeError(
257-
# f"error relationshipfield: {cls.model}'s {field} relationship is not true."
258-
# )
259-
# else:
260-
# setattr(instance, k, v)
261-
# return instance
262-
#
263-
# @classmethod
264-
# def update_model(cls, instance: Any, data: dict, session: Session) -> Any:
265-
# """
266-
# 更新数据之前调用
267-
# """
268-
# for k, v in data.items():
269-
# field = getattr(cls.model, k)
270-
# if isinstance(field.property, RelationshipProperty):
271-
# if field.property.direction == MANYTOMANY:
272-
# model = field.mapper.class_
273-
# pk = list(get_pk(model).values())[0]
274-
# childs = session.execute(select(model).where(pk.in_(v))).scalars().fetchall()
275-
# setattr(instance, k, childs)
276-
# elif field.property.direction == MANYTOONE:
277-
# field = get_real_column_field(field)
278-
# setattr(instance, field.key, v)
279-
# elif field.property.direction == ONETOMANY: # todo 暂时不考虑支持
280-
# # onetoone
281-
# if not getattr(field.property, "uselist"):
282-
# pass
283-
# else:
284-
# pass
285-
# else:
286-
# raise AttributeError(
287-
# f"error relationshipfield: {cls.model}'s {field} relationship is not true."
288-
# )
289-
# else:
290-
# setattr(instance, k, v)
291-
# return instance
292-
293-
# @classmethod
294-
# def get_clean_fields(cls, fields, need_many: bool = False):
295-
# """
296-
# 获取对外键进行处理过的列表,该方法主要用于数据处理
297-
# """
298-
# res = []
299-
# for i in fields:
300-
# if hasattr(i.property, "direction"):
301-
# if i.property.direction in (MANYTOMANY, ONETOMANY):
302-
# if need_many:
303-
# res.append(i)
304-
# else:
305-
# continue
306-
# if i.property.direction == MANYTOONE:
307-
# res.append(get_real_column_field(i))
308-
# else:
309-
# res.append(i)
310-
# return res
311-
312268
__list_sql = None
313269

314270
def queryset(self, request: Request):
@@ -322,6 +278,7 @@ async def list(
322278
page: int = 1,
323279
):
324280
base_queryset = self.queryset(request)
281+
base_queryset = self.queryset_filter(request, base_queryset)
325282
queryset = self.prefetch(request, base_queryset, self.get_list_distplay())
326283
datas = await queryset.limit(perPage).offset((page - 1) * perPage)
327284
res = []
@@ -340,13 +297,6 @@ async def get_instance(self, request: Request, pk: Any) -> Optional[Model]:
340297
queryset = self.prefetch(request, queryset, self.get_update_fields())
341298
return await queryset.first()
342299

343-
# @classmethod
344-
# def get_one_sql(cls, pks: list, need_many: bool = False):
345-
# if cls.__one_sql is None:
346-
# __list_display = cls.get_clean_fields(cls.update_fields, need_many)
347-
# cls.__one_sql = select(__list_display)
348-
# return cls.__one_sql.where(*pks)
349-
#
350300
def make_fields(self):
351301
if not self.fields.get("pk"):
352302
self.fields["pk"] = create_column("pk", self.model._meta.pk, self.prefix)
@@ -389,6 +339,9 @@ async def select_options(
389339
perPage: Optional[int],
390340
page: Optional[int],
391341
):
342+
"""
343+
外键的枚举获取值以及多对多获取对象列表
344+
"""
392345
return await self.selct_defs[name](request, pk, perPage, page)
393346

394347

fast_tmp/site/base.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,27 @@ def get_control(self, request: Request) -> Control:
8888

8989
class ModelFilter:
9090
name = ""
91+
type: Optional[str] = None
92+
label: Optional[str]
93+
clearable: Optional[bool]
94+
placeholder: Optional[str]
9195
_field: fields.Field = None
9296

9397
def queryset(self, request: Request, queryset: QuerySet, val: Any) -> QuerySet:
9498
return queryset
9599

96-
def __init__(self, name: str, field: fields.Field = None):
100+
def __init__(
101+
self,
102+
name: str,
103+
type: str = "input-text",
104+
label: str = None,
105+
clearable=None,
106+
placeholder=None,
107+
field: fields.Field = None,
108+
):
97109
self.name = name
98110
self._field = field
111+
self.type = type
112+
self.label = label or self.name
113+
self.clearable = clearable
114+
self.placeholder = placeholder

tests/test_example/test_example/admin.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,15 @@ class FieldTestingModel(ModelAdmin):
4444
)
4545

4646

47+
from fast_tmp.site.filter import ContainsFilter
48+
49+
4750
class BookModel(ModelAdmin):
4851
model = Book
4952
list_display = ("name", "author", "rating")
5053
create_fields = ("name", "author", "rating")
5154
update_fields = ("name", "author")
55+
filters = (ContainsFilter("name"),)
5256

5357

5458
class AuthorModel(ModelAdmin):

0 commit comments

Comments
 (0)