Skip to content

Commit

Permalink
Merge pull request #73 from zy7y/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
zy7y authored Jul 14, 2024
2 parents 9440d29 + 6ac7920 commit 021e2ec
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# 已支持从数据库表生成
- [x] SQLModel
- [x] Tortoise ORM
- [x] Vue
- [x] Vue、React
- [x] FastAPI 增加、删除、分页查询、详情查询、更新接口

# Generate Code
Expand Down
2 changes: 1 addition & 1 deletion dfs_generate/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.2.6"
__version__ = "0.2.7"
47 changes: 31 additions & 16 deletions dfs_generate/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
VUE_API_TS,
VUE_INDEX_VUE,
VUE_CRUD_TS,
REACT_CRUD_TSX
)
from dfs_generate.tools import to_pascal, tran, to_snake, to_camel

Expand Down Expand Up @@ -39,6 +40,13 @@ def _fast_crud_column(column):
return fmt


def _antd_crud_column(column):
name = to_camel(column["COLUMN_NAME"])
title = column["COLUMN_COMMENT"] or name
fmt = f"{{ title: '{title}', dataIndex: '{name}', key: '{name}', supportSearch: true}}"
return fmt


class Conversion:
def __init__(self, table_name, columns, uri):
self.table_name = table_name
Expand Down Expand Up @@ -77,14 +85,14 @@ def schema(self):
+ 'model_config = {"alias_generator": to_camel, "populate_by_name": True}'
)
return (
"\n".join(imports)
+ "\n\n"
+ RESPONSE_SCHEMA
+ "\n\n"
+ head
+ "\n"
+ "\n".join(fields)
+ "\n"
"\n".join(imports)
+ "\n\n"
+ RESPONSE_SCHEMA
+ "\n\n"
+ head
+ "\n"
+ "\n".join(fields)
+ "\n"
)

def router(self):
Expand All @@ -98,13 +106,19 @@ def vue_api_ts(self):

def vue_crud_ts(self):
columns = (
"{" + ",".join(_fast_crud_column(column) for column in self.columns) + "}"
"{" + ",".join(_fast_crud_column(column) for column in self.columns) + "}"
)
return VUE_CRUD_TS % columns

def vue_index_vue(self):
return VUE_INDEX_VUE % self.table

def react_crud_tsx(self):
columns = (
"[" + ",".join(_antd_crud_column(column) for column in self.columns) + "]"
)
return REACT_CRUD_TSX % (self.table, columns)

def gencode(self):
return {
"model.py": self.model(),
Expand All @@ -115,6 +129,7 @@ def gencode(self):
"api.ts": self.vue_api_ts(),
"crud.ts": self.vue_crud_ts(),
"index.vue": self.vue_index_vue(),
"react_curd.tsx": self.react_crud_tsx()
}


Expand Down Expand Up @@ -175,7 +190,7 @@ def _sqlmodel_field_repr(column, imports):

name = column["COLUMN_NAME"]
if kwargs.get("default", "") is None and "func.now" not in kwargs.get(
"sa_column", ""
"sa_column", ""
):
imports.add("from typing import Optional")
field_type = f"Optional[{_type}]"
Expand Down Expand Up @@ -281,12 +296,12 @@ def model(self):
if " " + field not in fields:
fields.append(" " + field)
return (
"\n".join(imports)
+ "\n\n"
+ head
+ "\n"
+ "\n".join(fields)
+ f"\n{' ' * 4}class Meta:\n{' ' * 8}table='{self.table_name}'"
"\n".join(imports)
+ "\n\n"
+ head
+ "\n"
+ "\n".join(fields)
+ f"\n{' ' * 4}class Meta:\n{' ' * 8}table='{self.table_name}'"
)

def dao(self):
Expand Down
109 changes: 102 additions & 7 deletions dfs_generate/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
支持ORM:[SQLModel](https://sqlmodel.tiangolo.com/)、[Tortoise ORM](https://tortoise.github.io/)
支持前端: [Vue](https://cn.vuejs.org/)
支持前端: [Vue](https://cn.vuejs.org/)、[React](https://react.dev/)
"""

RESPONSE_SCHEMA = """
Expand Down Expand Up @@ -270,6 +270,7 @@ async def delete_${router_name}_by_id(id: int) -> schema.Result[schema.$table]:
* dfs-generate 生成FastAPI Tortoise ORM / SQLModel、Vue3 CRUD代码
* dfs-generate Github: https://github.com/zy7y/dfs-generate
* Vue CRUD代码基于fast-crud,更多用法请查看其官方文档 http://fast-crud.docmirror.cn/
* @fast-crud/fast-crud": "^1.21.1"
*/
import { CreateCrudOptionsProps, CreateCrudOptionsRet, dict } from "@fast-crud/fast-crud";
import { addRequest, delRequest, editRequest, pageRequest } from "./api";
Expand All @@ -296,20 +297,18 @@ async def delete_${router_name}_by_id(id: int) -> schema.Result[schema.$table]:
* dfs-generate Github: https://github.com/zy7y/dfs-generate
* Vue CRUD代码基于fast-crud,更多用法请查看其官方文档 http://fast-crud.docmirror.cn/
*/
import { AddReq, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import type { AddReq, DelReq, EditReq, UserPageQuery, UserPageRes } from "@fast-crud/fast-crud";
import axios from "axios";
const url = "http://127.0.1:5000/%s";
export const pageRequest = async (query: UserPageQuery): Promise<UserPageRes> => {
const { limit, offset } = query.page;
const pageNumber = offset / limit + 1;
const pageSize = limit;
const { currentPage, pageNumber } = query.page;
const res = await axios.get(url, {
params: {
pageNumber,
pageSize,
...query.query
pageSize: currentPage,
...query.form
}
});
return {
Expand Down Expand Up @@ -379,3 +378,99 @@ async def delete_${router_name}_by_id(id: int) -> schema.Result[schema.$table]:
});
</script>
"""

REACT_CRUD_TSX = """
/**
* dfs-generate 生成FastAPI Tortoise ORM / SQLModel、React CRUD代码
* dfs-generate Github: https://github.com/zy7y/dfs-generate
* React CRUD代码基于antd-crud,更多用法请查看其官方文档 https://gitee.com/antdadmin/antd-crud
* @codeflex/antd-crud: "^1.0.6",
*/
import AntdCrud, { Actions, ColumnsConfig } from "@codeflex/antd-crud";
import { message } from "antd"
import axios from "axios";
import { useState } from "react";
const BASEURL = "http://127.0.0.1:5000/%s"
const handleUpdate = async (id: number, data: any) => {
const res = await axios.patch(BASEURL + "/" + id, data)
message.success("更新成功")
}
const handleCreate = async (data: any) => {
const res = await axios.post(BASEURL, data)
message.success("创建成功")
}
const handleDelete = async (id: number) => {
const res = await axios.delete(BASEURL + "/" + id)
message.success("删除成功")
}
export default function () {
const [state, setState] = useState({
data: [],
pageNumber: 1,
pageSize: 10,
total: 0,
})
const columns: ColumnsConfig<any> = %s
const actions: Actions<any> = {
onCreate: async (account) => {
await handleCreate(account)
await getPageData({})
},
onDelete: async (account) => {
await handleDelete(account.id)
await getPageData({})
},
onUpdate: async (account) => {
console.log(account, "update")
await handleUpdate(account.id, account)
await getPageData({})
},
onFetchList: async (currentPage, pageSize, totalPage, searchParams, sortKey, sortType) => {
setState({
...state,
pageNumber: currentPage,
pageSize
})
await getPageData({
pageSize,
pageNumber: currentPage,
...(searchParams ?? {}),
})
},
onDeleteBatch: async (rows) => {
message.warning("暂不支持批量删除")
},
};
const getPageData = async (params: {}) => {
const res = await axios.get(BASEURL, {params})
setState({
...res.data
})
}
return (
<AntdCrud
columns={columns}
dataSource={state.data}
actions={actions}
pageNumber={state.pageNumber}
pageSize={state.pageSize}
totalRow={state.total}
/>
)
}
"""
4 changes: 4 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Change Log
## Release v0.2.7 (2024-07-14)
- #29 基于[antd-crud](https://gitee.com/antdadmin/antd-crud)生成`React`代码完整管理页面操作
- 增加`fast-crud`版本说明(需安装指定版本、否则可能出现不兼容)

## Release v0.2.6 (2024-06-01)
- #68 修复每次打开需要配置链接

Expand Down
40 changes: 33 additions & 7 deletions tests/test_conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
_pydantic_field,
_sqlmodel_field_repr,
_tortoise_field_repr,
_fast_crud_column,
_antd_crud_column
)

# 假设的列数据,用于模拟从数据库获取的信息
Expand Down Expand Up @@ -77,8 +79,8 @@ def test_tortoise_conversion_model(tortoise_conversion_fixture):
assert "class Users(Model):" in model_code
assert 'id = fields.IntField(description="主键ID", pk=True)' in model_code
assert (
'name = fields.CharField(null=True, max_length=100, description="姓名")'
in model_code
'name = fields.CharField(null=True, max_length=100, description="姓名")'
in model_code
)


Expand All @@ -94,11 +96,11 @@ def test_sqlmodel_field_repr():
column = MOCK_COLUMNS[0] # 使用id字段作为测试
imports, field_code = set(), _sqlmodel_field_repr(column, set())
assert (
'id: Optional[int] = Field(default=None,primary_key=True,description="主键ID")'
== field_code
'id: Optional[int] = Field(default=None,primary_key=True,description="主键ID")'
== field_code
)
assert (
"from datetime import datetime" not in imports
"from datetime import datetime" not in imports
) # id字段不应触发默认时间戳逻辑


Expand All @@ -107,6 +109,30 @@ def test_tortoise_field_repr():
column = MOCK_COLUMNS[1]
field_code = _tortoise_field_repr(column)
assert (
'name = fields.CharField(null=True, max_length=100, description="姓名")'
== field_code
'name = fields.CharField(null=True, max_length=100, description="姓名")'
== field_code
)


@pytest.mark.parametrize("column_data,expected", [
({"COLUMN_NAME": "user_name", "COLUMN_COMMENT": "User's Name"},
"userName: { title: 'User's Name', type: 'text', search: { show: true }}"),
({"COLUMN_NAME": "is_active", "COLUMN_COMMENT": ""},
"isActive: { title: 'isActive', type: 'text', search: { show: true }}"),
({"COLUMN_NAME": "last_login_dt", "COLUMN_COMMENT": "Last Login Date & Time"},
"lastLoginDt: { title: 'Last Login Date & Time', type: 'text', search: { show: true }}"),
])
def test_fast_crud_column(column_data, expected):
assert _fast_crud_column(column_data) == expected


@pytest.mark.parametrize("column_data,expected", [
({"COLUMN_NAME": "user_name", "COLUMN_COMMENT": "User's Name"},
"{ title: 'User's Name', dataIndex: 'userName', key: 'userName', supportSearch: true}"),
({"COLUMN_NAME": "is_active", "COLUMN_COMMENT": ""},
"{ title: 'isActive', dataIndex: 'isActive', key: 'isActive', supportSearch: true}"),
({"COLUMN_NAME": "last_login_dt", "COLUMN_COMMENT": "Last Login Date & Time"},
"{ title: 'Last Login Date & Time', dataIndex: 'lastLoginDt', key: 'lastLoginDt', supportSearch: true}"),
])
def test_antd_crud_column(column_data, expected):
assert _antd_crud_column(column_data) == expected

0 comments on commit 021e2ec

Please sign in to comment.