Skip to content

Commit 5fdcb1c

Browse files
committed
优化:
默认参数是函数时候页面该值不为必填 创建的时候如果该参数为空则使用默认函数生成值 增加单元测试
1 parent b0798f6 commit 5fdcb1c

File tree

12 files changed

+114
-56
lines changed

12 files changed

+114
-56
lines changed

fast_tmp/site/__init__.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,9 @@ async def get_app_page(self, request: Request) -> Page:
214214
async def update(self, request: Request, pk: str, data: Dict[str, Any]) -> Model:
215215
obj = await self.get_instance(request, pk)
216216
err_fields = {}
217-
for field_name in self.update_fields:
218-
control = self.get_formitem_field(field_name)
217+
for field_name, field in self.get_update_fields().items():
219218
try:
220-
await control.set_value(request, obj, data[field_name])
219+
await field.set_value(request, obj, data[field_name])
221220
except ValidationError as e:
222221
err_fields[field_name] = str(e)
223222
except TmpValueError as e:

fast_tmp/site/base.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ async def set_value(self, request: Request, obj: Model, value: Any) -> Optional[
5252
"""
5353
pass
5454

55-
def validate(self, value: Any) -> Any:
55+
def validate(self, value: Any, is_create=False) -> Any:
5656
"""
5757
对数据进行校验
58+
is_create: 当model为创建的时候,如果默认值是函数,则会传空过来,这个时候需要调用函数生成值。
5859
"""
5960
return value
6061

@@ -135,10 +136,11 @@ def get_formitem(self, request: Request, codenames: Iterable[str]) -> FormItem:
135136
description=self.description,
136137
placeholder=self.placeholder,
137138
)
138-
if not self._field.null: # type: ignore
139-
self._control.required = True
140-
if self._field.default is not None: # type: ignore
141-
self._control.value = self.orm_2_amis(self._field.default) # type: ignore
139+
if not callable(self._field.default): # type: ignore
140+
if not self._field.null: # type: ignore
141+
self._control.required = True
142+
if self._field.default is not None: # type: ignore
143+
self._control.value = self.orm_2_amis(self._field.default) # type: ignore
142144
return self._control
143145

144146
def options(self):
@@ -161,7 +163,7 @@ def get_column_inline(self, request: Request) -> Column:
161163
return self._column_inline
162164

163165
async def set_value(self, request: Request, obj: Model, value: Any):
164-
value = await self.validate(value)
166+
value = await self.validate(value, is_create=request.method == "POST")
165167
setattr(obj, self.name, value)
166168

167169
async def get_value(self, request: Request, obj: Model) -> Any:
@@ -182,7 +184,12 @@ def __init__(self, name: str, field: fields.Field, prefix: str, **kwargs):
182184
self.description = kwargs.get("description") or description
183185
self.placeholder = kwargs.get("placeholder") or placeholder
184186

185-
async def validate(self, value: Any) -> Any:
187+
async def validate(self, value: Any, is_create=False) -> Any:
188+
if not value and is_create:
189+
if (
190+
callable(self._field.default) and not self._field.null # type: ignore
191+
): # 不为空且默认值是函数的时候,前段页面如果传null则使用默认值
192+
return self._field.default() # type: ignore
186193
value = self.amis_2_orm(value)
187194
self._field.validate(value) # type: ignore
188195
return value

fast_tmp/site/field.py

Lines changed: 28 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,8 @@ class BooleanControl(IntEnumControl):
118118
def options(self) -> List[str]:
119119
return ["True", "False"]
120120

121-
async def validate(self, value: Any) -> Any:
122-
return self.amis_2_orm(value)
123-
124121
def amis_2_orm(self, value: Any) -> Any:
125-
if (value == "None" or not value) and self._field.null: # type: ignore
122+
if not value and self._field.null: # type: ignore
126123
return None
127124
if value == "True":
128125
return True
@@ -132,7 +129,7 @@ def amis_2_orm(self, value: Any) -> Any:
132129

133130
def orm_2_amis(self, value: Any) -> Any:
134131
if value is None:
135-
return "None"
132+
return
136133
elif value:
137134
return "True"
138135
return "False"
@@ -157,18 +154,16 @@ def get_column_inline(self, request: Request) -> Column:
157154
self._column_inline.quickEdit.format = "YYYY-MM-DD HH:mm:ss"
158155
return self._column_inline
159156

160-
def amis_2_orm(self, value: Any) -> Any:
161-
if value == "None" or not value: # type: ignore
162-
if self._field.null:
163-
return None
164-
else:
165-
raise TmpValueError(f"{self.label} 不能为 {value}")
166-
return datetime.datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
157+
def amis_2_orm(self, value: str) -> Any:
158+
if value:
159+
return datetime.datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
160+
if self._field.null: # type: ignore
161+
return None
162+
raise TmpValueError(f"{self.label} 不能为 {value}")
167163

168164
def orm_2_amis(self, value: datetime.datetime) -> Any:
169-
if value is None:
170-
return None
171-
return value.strftime("%Y-%m-%d %H:%M:%S")
165+
if value is not None:
166+
return value.strftime("%Y-%m-%d %H:%M:%S")
172167

173168

174169
class DateControl(BaseAdminControl):
@@ -187,13 +182,12 @@ def get_column_inline(self, request: Request) -> Column:
187182
return self._column_inline
188183

189184
def amis_2_orm(self, value: Any) -> Any:
190-
if value == "None" or not value: # type: ignore
191-
if self._field.null:
192-
return None
193-
else:
194-
raise TmpValueError(f"{self.label} 不能为 {value}")
195-
year, month, day = value.split("-")
196-
return datetime.date(int(year), int(month), int(day))
185+
if value:
186+
year, month, day = value.split("-")
187+
return datetime.date(int(year), int(month), int(day))
188+
if self._field.null: # type: ignore
189+
return None
190+
raise TmpValueError(f"{self.label} 不能为 {value}")
197191

198192
def orm_2_amis(self, value: datetime.date) -> Any:
199193
if value is None:
@@ -219,19 +213,18 @@ def get_column_inline(self, request: Request) -> Column:
219213
return self._column_inline
220214

221215
def amis_2_orm(self, value: Any) -> Any:
222-
if not value:
216+
if value:
217+
return datetime.time.fromisoformat(value)
218+
if self._field.null: # type: ignore
223219
return None
224-
return datetime.time.fromisoformat(value)
220+
raise TmpValueError(f"{self.label} 不能为 {value}")
225221

226222
def orm_2_amis(self, value: Optional[datetime.time]) -> Any:
227-
if value is None:
228-
return None
229-
if callable(value):
230-
return value().strftime("%H:%M:%S")
231-
return value.strftime("%H:%M:%S")
223+
if value is not None:
224+
return value.strftime("%H:%M:%S")
232225

233226

234-
class JsonControl(TextControl): # fixme 用代码编辑器重构?
227+
class JsonControl(TextControl):
235228
def amis_2_orm(self, value: Any) -> Any:
236229
if not value:
237230
return None
@@ -244,7 +237,10 @@ def get_formitem(self, request: Request, codenames: Iterable[str]) -> FormItem:
244237
if not self._control:
245238
super().get_formitem(request, codenames)
246239
self._control.validations = "isJson"
247-
self._control.value = "{}" # fixme jsonfield不能为空
240+
if not callable(self._field.default): # type: ignore
241+
self._control.required = True # jsonfield不能为空不然写数据库必爆炸
242+
if not self._control.value: # 如果有默认值则已经在父类里面被调用
243+
self._control.value = "{}"
248244
return self._control
249245

250246
def get_column_inline(self, request: Request) -> Column:
@@ -422,7 +418,7 @@ def amis_2_orm(self, value: List[dict]) -> Any:
422418
return value.split(",")
423419
return [i["value"] for i in value]
424420

425-
async def validate(self, value: Any) -> Any:
421+
async def validate(self, value: Any, is_create=False) -> Any:
426422
if value is not None:
427423
pks = self.amis_2_orm(value)
428424
if len(pks) > 0:

task.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
12. 检查是否存在is_active为false的超级用户可以登录的情况
1515
13. 增加token解析的更新时间,这样可以检查密码是否过期(根据用户的更新时间和生成token的时间进行比较而判断)
1616
14. 测试字段报错检查
17+
15. 对时间类,如果是auto_now_add为true是否要必填?
1718

1819
# admin管理页面缺少功能
1920

tests/admin.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,16 @@ class DecModel(ModelAdmin):
7171

7272
class IntEnumAdmin(ModelAdmin):
7373
model = IntEnumField
74-
list_display = ("int_enum_1", "int_enum_2", "bool_1", "bool_2")
74+
list_display = (
75+
"int_enum_1",
76+
"int_enum_2",
77+
"bool_1",
78+
"bool_2",
79+
"datetime_1",
80+
"datetime_2",
81+
"datetime_3",
82+
"datetime_4",
83+
)
7584
create_fields = list_display
7685
update_fields = list_display
7786
inline = list_display

tests/test_example/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ async def create_user():
3030

3131
@app.post("/form-test")
3232
async def test_form(request: Request):
33-
print(await request.json())
33+
await request.json()
3434
return BaseRes()
3535

3636

tests/test_example/test_example/admin.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class FieldTestingModel(ModelAdmin):
1818
"birthday",
1919
"config",
2020
"max_time_length",
21+
"def_time",
22+
"def_time2",
2123
)
2224
inline = (
2325
"name_inline",
@@ -28,20 +30,26 @@ class FieldTestingModel(ModelAdmin):
2830
"birthday",
2931
"config",
3032
"max_time_length",
33+
"def_time",
34+
"def_time2",
3135
)
3236
create_fields = (
3337
"name",
3438
"age",
3539
"desc",
3640
"married",
41+
"married_inline",
3742
"degree",
3843
"degree_inline",
3944
"gender",
4045
"created_time",
4146
"birthday",
4247
"config",
4348
"max_time_length",
49+
"def_time",
50+
"def_time2",
4451
)
52+
update_fields = create_fields
4553

4654

4755
class BookModel(ModelAdmin):

tests/test_example/test_example/models.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class FieldTesting(Model):
162162
avator = fields.BinaryField(null=True) # 头像
163163
config = fields.JSONField(null=True)
164164
waiting_length = fields.TimeDeltaField(null=True) # 等待时长
165-
max_time_length = fields.TimeField(default=datetime.time()) # 最长游戏时长
165+
max_time_length = fields.TimeField(default=datetime.time) # 最长游戏时长
166166
uuid = fields.UUIDField(default=uuid.uuid4)
167167
level = fields.SmallIntField(default=0)
168168
name_inline = fields.CharField(null=True, max_length=32)
@@ -171,14 +171,16 @@ class FieldTesting(Model):
171171
birthday_inline = fields.DateField(null=True)
172172
money_inline = fields.DecimalField(null=True, max_digits=10, decimal_places=2)
173173
height_inline = fields.FloatField(null=True)
174-
married_inline = fields.BooleanField(null=True, default=False)
174+
married_inline = fields.BooleanField(null=True)
175175
gender_inline = fields.CharEnumField(Gender, null=True)
176176
degree_inline = fields.IntEnumField(Degree, null=True, description="degree")
177177
game_length_inline = fields.BigIntField(null=True, default=0) # 游戏时长,按秒计算
178178
avator_inline = fields.BinaryField(null=True) # 头像
179179
config_inline = fields.JSONField(null=True)
180180
waiting_length_inline = fields.TimeDeltaField(null=True) # 等待时长
181-
max_time_length_inline = fields.TimeField(null=True, default=datetime.time()) # 最长游戏时长
181+
max_time_length_inline = fields.TimeField(null=True, default=datetime.time) # 最长游戏时长
182182
uuid_inline = fields.UUIDField(null=True)
183183
level_inline = fields.SmallIntField(null=True, default=0)
184-
created_time = fields.DatetimeField(auto_now_add=True, null=True)
184+
created_time = fields.DatetimeField(auto_now_add=True)
185+
def_time = fields.DatetimeField(null=True) # 测试datetime为空的返回值
186+
def_time2 = fields.DatetimeField(default=datetime.datetime.now)

tests/test_field.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"""
22
测试所有类型的字段的写入和读取
33
"""
4+
import datetime
5+
46
from tests.base import BaseSite
57

68

@@ -35,7 +37,12 @@ async def test_intenum(self):
3537
data = response.json()
3638
assert data["status"] == 0
3739
# 测试写入数据
38-
role_data = {"int_enum_2": "two", "bool_2": "False"}
40+
role_data = {
41+
"int_enum_2": "two",
42+
"bool_2": "False",
43+
"datetime_4": datetime.datetime.fromtimestamp(0).strftime("%Y-%m-%d %H:%M:%S"),
44+
"datetime_3": datetime.datetime.fromtimestamp(0).strftime("%Y-%m-%d %H:%M:%S"),
45+
}
3946
response = await self.client.post("/admin/intenumfield/create", json=role_data)
4047
assert response.status_code == 200
4148
data = response.json()
@@ -49,9 +56,36 @@ async def test_intenum(self):
4956
self.assertEqual(data["data"]["items"][0]["int_enum_1"], None)
5057
assert data["data"]["items"][0]["int_enum_2"] == "two"
5158
assert data["data"]["items"][0]["bool_2"] == "False"
52-
assert data["data"]["items"][0]["bool_1"] == "None"
53-
role_data = {"int_enum_2": "three", "bool_1": "xx"}
59+
assert data["data"]["items"][0]["bool_1"] is None
60+
assert data["data"]["items"][0]["datetime_1"] is None
61+
assert data["data"]["items"][0]["datetime_3"] == datetime.datetime.fromtimestamp(
62+
0
63+
).strftime("%Y-%m-%d %H:%M:%S")
64+
assert data["data"]["items"][0]["datetime_4"] == datetime.datetime.fromtimestamp(
65+
0
66+
).strftime("%Y-%m-%d %H:%M:%S")
67+
assert datetime.datetime.strptime(
68+
data["data"]["items"][0]["datetime_2"], "%Y-%m-%d %H:%M:%S"
69+
)
70+
role_data = {
71+
"int_enum_2": "three",
72+
"bool_1": "xx",
73+
"datetime_3": datetime.datetime.fromtimestamp(0).strftime("%Y-%m-%d %H:%M:%S"),
74+
}
5475
response = await self.client.post("/admin/intenumfield/create", json=role_data)
5576
assert response.status_code == 200
5677
data = response.json()
57-
self.assertEqual({"data": {}, "msg": "one: 1\ntwo: 2 不能为 three", "status": 400}, data)
78+
self.assertEqual(
79+
{
80+
"data": None,
81+
"errors": {
82+
"bool_1": "bool_1 不能为 xx",
83+
"bool_2": "bool_2 不能为 None",
84+
"int_enum_2": "one: 1\ntwo: 2 不能为 three",
85+
"datetime_4": "datetime_4 不能为 None",
86+
},
87+
"msg": "",
88+
"status": 422,
89+
},
90+
data,
91+
)

tests/test_perm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,6 @@ async def test_book(self):
260260
self.assertEqual(response.status_code, 200)
261261
response = await self.client.get("/admin/book/list?page=1&perPage=10")
262262
self.assertEqual(
263-
response.json(),
264263
{
265264
"status": 0,
266265
"msg": "",
@@ -277,6 +276,7 @@ async def test_book(self):
277276
"total": 1,
278277
},
279278
},
279+
response.json(),
280280
)
281281
# delete
282282
response = await self.client.delete("/admin/book/delete/1")

0 commit comments

Comments
 (0)