都写过,我还用 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 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)
return {
page: page,
per_page: per_page,
items: [ serizlier_func(obj) for obj in page.object_list]
}
为何说浅层封装很重要?
因为为了一小片功能引入一个又一个库会带来额外维护负担, 我可以极短的代码实现, 就不需要引入一个库来专门解决一个小问题.
姿势 # 02 关于性能+异步
Django的ORM慢这个是公认的没啥好说的, 但我就想问问, IO Bound的服务配置好数据库连接池直接上Gevent直接同步代码变异步, 也算能打的好伐?
姿势 # 03 关于神器 repl - iPython
在业务升级的时候, 经常要写一些一次性脚本去刷数据/做配置
这个时候我一般直接进入容器 or ssh到机器那边直接进入ipython (自动把需要的模块全部导入进来), 然后复制脚本刷数据/配置数据完毕. 喝茶休息.
你用 Java 这种静态语言你就没法子这么舒服的做(如果可以的话,请告诉我) 毕竟我也写过Spring项目, 还是Kotlin版本的
姿势 # 04 django-restframework + django-filter 让你批量开管理端接口from rest_framework import generics
from django_filters import rest_framework as filters
from myapp import Product
class ProductFilter(filters.FilterSet):
min_price = filters.NumberFilter(field_name="price", lookup_expr='gte')
max_price = filters.NumberFilter(field_name="price", lookup_expr='lte')
class Meta:
model = Product
fields = ['category', 'in_stock', 'min_price', 'max_price']
class ProductList(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = (filters.DjangoFilterBackend,)
filterset_class = ProductFilter
'category', 'in_stock', 'min_price', 'max_price' 好了, 随你前端query不香嘛?
0xEE 扩展阅读
关于流行的框架/语言/工具, 大多都是 梅须逊雪三分白, 雪却输梅一段香
甲之蜜糖, 乙之砒霜.
关于 静态语言和动态语言一些看法无与童比:用 Type Annotation 提升你的 Python 代码健壮性zhuanlan.zhihu.com
关于 Flask 和 Django的一些看法无与童比:Django 和 Flask 这两个框架在设计上各方面有什么优缺点?zhuanlan.zhihu.com