很多人都说,如果开发对性能要求不高的小型web项目,Django写起来更快更省事儿。
对此我一直不大理解(不排除是以为我了解有限,欢迎详细指教):
如果光论基础语法,Python确实比Java要简洁很多。但是具体到web开发的领域,我的感觉似乎就反过来了。
很多web后端功能,在SpringBoot里面就是一行@注解搞定的,Django却要在几个文件里面来回改配置。
例如:开通一个网络接口,SpringBoot一个注解搞定 @RequestMapping( "/url" ),如果你要把类上面的 @RestController 也算上那就是两个。
为网络接口开放跨域授权,SpringBoot一个注解搞定 @CrossOrigin(origins = "*" )
而在Django里面,开通一个网络接口却要在 urls.py 与 views.py 之间来来回回写配置。
此外,在SpringBoot项目中,返回json给前端,根本不需要你自己处理,在Controller接口中直接return对象就行了,框架会自动帮你转成json。而在Django项目中,还要自己调用下 json.dumps 函数。
请教下:是因为我对Django框架的了解不够(例如:有更简便的注解配置方式,只是我自己百度没查到),还是因为SpringBoot的高度封装化其实已经走在Django前面了?……
111 个回答
都写过,我还用 kotlin 写过 spring
仅侧重比较 spring 熟手和 django 熟手的体验......
- 主观来说,是这样的. (具体比较看下文)。
- 你只比较了 view 层,其实通过浅封装直接返回 dict 然后用 response 包装
- 具体表现在可以用更短的代码描述业务逻辑。
- 比 jpa 更舒服的 orm 体验和自带 migration
- 不需要遵循 java 系列专属的 dto dmo repo 在各种文件之间反复横跳
- 发布打包成 wheel 包,线上只需要配置文件和一个 wheel 包
如果不是 cpu bound 的小项目,django 用起来会舒服很多,当然,这也取决于使用者。
虽然,python 的性能一言难尽
但,java 容易一不小心就把小项目写成了中等项目......
比如,项目规模本身不大,文件数量 / 代码行数 / 可读性,动态语言是比静态语言表达力更强(但也取决于使用者). 再比如,用 jpa/spring 框架代码行数出奇的多..... 同样的逻辑用 django 来写就很精简(但也取决于使用者)
编程语言之争其实意义不是很大,就拿表达力这个词来说,
当我说动态语言表达能力强指的是对于使用者来说可以短时间内不需要特别关注内存 / 线程 /cpu 这些,专注于业务逻辑的开发。
当我说静态语言表达能力强指的是对于计算机来说可以更好的压榨计算机性能
其实很多时候框架 / 工具的优缺点并不是框架的优缺点,而是使用者的优缺点。
======== 更新
看到楼下 @蜗牛 给了一些spring boot 的第三方库的事例, 那我也补充一些django的第三方库吧.
首先, 我认同 Java 的开源库确实比Python的开源库在广度上 略胜一筹,
但如果说的不是SpringCloud, 我确实没觉得Python的Django生态差到哪里去了.....
姿势 # 01 浅层封装就可以达到你想要的效果
楼下的 @蜗牛提出了一个去掉 java service 层的方法, 需要用 myabatis-plus
@GetMapping("/list_user")
public Object listUser(Integer pageNum,Integer pageSize) {
PageHelper.startPage(pageNum,pageSize);
List<User> list = userMapper.selectList();
return list;
}
其实Django写这个真的很简单. 连第三方库都不需要, 几行业务代码+40来行封装代码
def list_user(request, condition1, condition2):
users = User.objects.filter(Q(condition1), Q(condition2))
return render_pagination_json(users, serializer_user)
当然你这里需要编写业务相关的序列器
def serializer_user(user):
return unpack_obj(user, "id", "nickname","other")
要做到这样只需两步
准备工作1 封装一个工具类unpack_obj用来从object里面常见序列器 (5行代码)
def unpack_obj(obj, *args):
if len(args) == 1 and isinstance(args[0], (list, tuple)):
fields = args[0]
else:
fields = args
return {field: getattr(obj, field) for field in fields}
准备工作2 在MiddleWare层将字典转成json, 或者写render_pagination_json方法 (伪代码)
def render_pagination_json(qs, serizlier_func) -> JsonResponse:
# page, per_page 可以从threadlocal里面拿, 或者直接传入request对象拿
page = g.page
per_page = g.per_page
paginator = Paginator(qs.all(), per_page)
# 这里可能要依据具体业务情况抛异常到外部处理
page = paginator.get_page(page)