SQLite 3.22.0 -3.26.0 2018 年新增加的 SQL 功能

SQLite 是一个被大家低估的数据库,但有些人认为它是一个不适合生产环境使用的玩具数据库。事实上,SQLite 是一个非常可靠的数据库,它可以处理 TB 级的数据,但它没有网络层。接下来,本文将与大家共同探讨 SQLite 在过去一年中最新的 SQL 功能。

SQLite “只是”一个库,它不是传统意义上的服务器。因此,在某些场合下,它确实不合适。但是,在相当多的其他场合,它却是最合适的选择。SQLite 号称是部署和使用最广泛的数据库引擎。我认为这很有可能,因为 SQLite 没有版权的限制。无论何时,只要开发者想使用 SQL 在文件中存储结构化的数据,SQLite 应是首选方案。

SQLite 的 SQL 方言也非常强大。它比 MySQL 早四年就开始支持 with 语句。最近,它还实现了对于窗口函数的支持,这仅仅比 MySQL 晚五个月。

接下来,本文将介绍 SQLite 在 2018 年新增加的 SQL 功能,也就是 SQLite 从版本 3.22.0 到 3.26.0 所新增加的 SQL 功能。

具体内容包括:

  1. 布尔字面量和判断

  2. 窗口函数

  3. Filter子句

  4. Insert … on conflict (“Upsert”)

  5. 重命名列

  6. 在Modern-SQL.com上接下来

布尔变量和判断

SQLite支持“假”布尔值:它接受Boolean作为类型的名称,但它将其当作整数看待(这一点非常类似于MySQL)。真值true和false分别由数值1和0表示(这一点和C语言一样)。

从版本3.23.0开始,SQLite将关键字true和false分别用数字1和0表示,并支持is [not] true | false的判断语句。现在,它不再支持关键字unknown。开发者可以使用空值null来代替,因为unknown和null的布尔值是一样的。

在INSERT和UPDATE语句中,字面量true和false可以大大提高values和set子句的可读性。

is [not] true | false这个判断语句很有用,它与比较操作的含义不一样:

我们来比较一下
WHERE c <> FALSE
WHERE c IS NOT FALSE

在上面的例子中,如果c是null, 那么c <> false的结果是unknown.

这是因为WHERE子句只接受结果为true的值,它会过滤掉结果为false或unknown的值。这样,它就会把对应的行从结果中去掉。

与此相对应,如果c是null,那么,c is not false的判断结果是true。因此,第二个WHERE子句也将包含c是null的行。

要达到同样的效果,您可以采用的另外一种方法是增加单独处理null值的子句。也就是使用语句:
WHERE c <> FALSE   OR c IS NULL

这种形式的语句更长并且有一些冗余语句(c被使用了两次)。长话短说,可以使用is not false判断来替代这个or…is-null的语句。更详细的内容,请参考“Binary Decisions Based on Three-Valued Results”。

SQLite中对布尔字面量和布尔判断的支持现在和其他开源数据库接近,唯一的差距是SQLite不支持is[not] unknown(你可以使用is [not] null来代替)。有趣的是,这些功能在下面提到的商用产品中还不可用。

0:只支持true,false.不支持notknown,如果需要,用null代替

1:不支持is [not] unknown,如果需要,用is [not] null代替

窗口函数

SQLite 3.25.0引入了窗口函数。如果你知道窗口函数,那么也知道这是一件大事。如果你不了解窗口功能,请你自己学习如何使用。这篇文章不会具体解释窗口函数,但请相信:它是最重要的“现代”SQL特性。

SQLite对over子句的支持与其他数据库非常接近。唯一值得注意的限制是range语句不支持数字或间隔距离(仅支持current row和unbounded preceding|following)。在发布sqlite 3.25.0时,SQL Server和PostgreSQL具有同样的限制。PostgreSQL 11消除了这一限制。

0:没有变化

1:Range范围定义不支持datetime类型

2:Range范围不接受关键字 (只支持unbounded和current row)

SQLite对于窗口函数的支持在业界是领先的。它不支持的功能在其他一些主要产品中也同样不支持(在聚合中语句中的distinct,width_bucket, respect|ignore nulls和from first|last等语句)。

0:同样没有ORDER BY 语句

1:不允许负偏移量,nulls的特定处理:lead(, ‘IGNORE NULLS’),这里是字符串参数

2:没有缺省值(第三个参数),不支持respect|ignore nulls语句

3:不允许负偏移量,不支持ignore nulls语句

4:不允许负偏移量

5:不支持respect|ignore nulls语句

6:不允许负偏移量,不支持respect|ignore nulls语句

7:nulls的特定处理:first_value(, 1, null, ‘IGNORE NULLS’) ,这里是字符串参数。

8:不支持ignore nulls语句

9:不支持ignore nulls语句和from last语句

过滤语句

虽然filter语句只是语法糖——你也可以很容易地使用表达式来获得相同的结果——我认为它也是必不可少的语法糖,因为它能使人们更加容易地学习和理解SQL语句。

看看下面的select子句,您觉得哪一个更容易理解?

SELECT SUM(revenue) total_revenue     , SUM(CASE WHEN product = 1                 THEN revenue            END          ) prod1_revenue   ...
SELECT SUM(revenue) total_revenue     , SUM(revenue) FILTER(WHERE product = 1) prod1_revenue   ...

此示例很好地总结了filter子句的作用:它是聚合函数的后缀,可以在进行聚合之前根据特定条件,过滤掉相应的行。pivot技术是filter子句最常见的用例。这包括将实体属性值(EAV)模型中的属性转换为表格的列,如果想了解更多的内容,可以参考链接“filter-Selective Aggregates”(https://modern-sql.com/feature/filter)。

SQLite 从版本3.25.0开始,在使用over子句的聚合函数中支持了filter子句,但是在使用group by子句的聚合函数中还不支持。不幸的是,这意味着您仍然无法在SQLite中使用filter语句来处理上述情况。你必须像以前一样使用case表达式。我真的希望SQLite在这一点上能尽快做到。

Insert … on conflict (“Upsert”)

SQLite 从版本3.24.0开始,引入了“upsert”概念:它是一个insert语句,可以优雅地处理主键和唯一约束的冲突。您可以选择忽略这些冲突(在on conflict语句中什么都不做)或者更新当前行(在on conflict语句中执行更新操作)。

这是一个特有的SQL扩展,即它不是标准SQL的一部分,因此在下面的矩阵中是灰色的。但是,SQLite遵守与PostgreSQL相同的语法来实现此功能0。该标准提供了对merge语句的支持。

与PostgreSQL不同,SQLite在以下语句中存在问题。
INSERT INTO targetSELECT *  FROM source    ON CONFLICT (id)    DO UPDATE SET val = excluded.val
根据说明文档,这是因为解析器无法判断关键字ON是SELECT语句的连接约束还是upsert子句的开头。你可以通过向查询中添加子句来解决,例如where true。
INSERT INTO targetSELECT *  FROM source WHERE true    ON CONFLICT (id)    DO UPDATE SET val = excluded.val

0:同样记录insert、update、delete和merge操作的错误信息 (“DML error logging”)

1:On conflict语句不能紧挨查询的from语句,如果需要,可以添加  where true语句来分隔。

重命名列

SQLite引入的另一个特有功能是重命名基准数据库表中的列1。标准的SQL不支持此类功能2。

SQLite遵循其他产品常用的语法来重命名列:

ALTER TABLE … RENAME COLUMN … TO

0:请查阅 sp_rename.

其他消息

在2018年,SQLite除了在SQL语法上的变化,还有一些应用程序接口(API)的变化。你可以查阅sqlite.com(https://www.sqlite.org/news.html)上的新闻部分来了解更详细的消息。

脚标:

  • 0:SQLite通常遵循PostgreSQL语法,Richard Hipp将此称为PostgreSQL会怎么做(WWPD)。

  • 1:基准数据库表是指用Create table语句创建的数据库表。派生的数据库表(如Select语句返回的查询结果集)中的列名可以通过SELECT语句、FROM语句或WITH语句来进行改变

  • 2:据我所知,也许可以通过可更新视图或派生的列来模拟该功能。 

文章来源:网络

转自:

裁员、清货、关门,盒马到底怎么了?

最近,各地盒马撤柜关门的消息,源源不断地冒出来。
有网友发现,自己买的盒马商品没人送货。送来的东西日期不新鲜,种类也变少了,爱喝的苹果汁下架了,常买的鸡肉也断货了。
就连我们办公室很多同事,也发现买到临期产品的概率变高了。
他还表示,这在曾经追求高质量的盒马,是绝不会发生的。
当有人贴出盒马货架被清空,既没人补货,店里也没有顾客的照片时。
差评君意识到这事有点不对头了啊。
可就在 3 个月前,盒马 CEO 侯毅还放出了豪言壮语,未来盒马的使命是 10 年 1 万亿和网友、同事的所见所闻一对比,这矛盾和冲突感,妥妥得拉满了。
差评君也大概了解了一下,去年 5 月的时候,盒马憋住一口气要上市,可惜最后没憋住,从那之后,似乎就在不断漏气了。
甚至于,一度传出了阿里要出售盒马的传闻。
虽然官方立马跳出来辟谣了,说没有的事。
但稍微留意一下,确实能发现盒马这日子是不太好过。
开头网友传的盒马关门,确实是存在的, 2 月底大连盒马门店就宣布停业。不过,盒马一向开关门速度飞快,效益不好了就直接砍掉。
根据知危编辑部采访到的武汉员工的说法, 3 月份,武汉还要再关 3 家。
不光是对亏钱的门店下手,在日常生活中,盒马也是能省则省。
 在一些帖子的下方,就有员工吐槽过盒马近乎离谱的省钱法子。
比如封厕所、不开门就不开灯,一关门立马关灯、一个人顶十个人用。巴不得一张厕纸,撕成两份使。
这省钱的算盘,还打到了员工的工资和合同上。
2 月初的时候,合肥等城市的门店,就只招收小时工或者兼职。像合肥后场拣货工,每件从 0.26 元,降到了 0.17 元。全国各地降薪幅度都在 20% 左右。
同时,盒马试图把正式员工转成外包三方员工
知危编辑部采访的武汉门店员工就告诉咱们,他在 2 月 18 号就收到了转临时工的通知。
取消五险一金、节假日三倍薪资、年假、十三薪,转为三方合同。要是不同意,就自己拍屁股滚蛋( 没有 N+1 )
 “ 有员工同意转了,还有哭着签字的。 ” 
受访者估算了一下,按一家店 20 个员工算,一年能给盒马省 40 万元。
这边疯狂地压榨员工,在消费者那边,盒马也是各种抠抠搜搜。
 以前免费提供的包装袋,现在每单强制收 1 元。在北京、南京、长沙的盒马,免送费门槛还升到了 99 元。
对于很多习惯在盒马买菜做饭的人来说, 99 元的凑单门槛能要了他们的命。。
大家实在想不通了,怎么大手大脚的阿里富哥儿,兜里好像突然没钱了。
如果我们看数据,会发现虽然盒马整体仍在亏损,但前年亏损已经在变少了。侯毅还在员工全员信中透露,其中盒马鲜生单个业务,前年甚至已经盈利。
按理来说,日子应该要慢慢好起来了,结果去年阿里一拆分,盒马独立了出来。
离开了大家庭之后,盒马的日子也开始紧巴起来了,如何盈利,成了当务之急。
所以,一整年时间,盒马都在做各种尝试。
 在 9 月份前,盒马想到的赚钱法子是把炮口对准山姆,去抢中产的钱。
先对标山姆推出了每年 658 元的钻石会员。还搞了一场轰轰烈烈的移山运动,正面比价、比货,打出半折的优惠。
最离谱的是跑到山姆门口,一车一车地往盒马运人。。。
虽然没伤到山姆分毫,但这招棋也算给盒马带来了不少好处。根据瑞泽洞察统计的数据,移山期间,盒马 APP 周均日活涨了 13.3% ,山姆也小涨了 3.9% 。
很多人以为,和山姆的这场贴身肉搏已经够猛的了。
结果没想到,移山结束才一个月,盒马又上新一系列大开大合的操作。
盒马干脆半放弃了自己的偏高价,重品质定位,打算用极致的低价硬刚到底。
去年 10 月,整了个全面 “ 折扣化 ” ,全场 5000 多款商品降价甩卖,之后连成本极高的生鲜价格都被打下来了。
随便举两个例子,以前卖 79 元的草莓盒子,现在只要 59 元、 39.9 的肥牛片降到了 31.9 。
面对一直居高不下的配送成本,盒马也选择重拳出击。
一位接近盒马的人士对知危表示,线上订单如果没到 99 元,对盒马来说送一单亏一单
 不巧的是,很多店铺的线上订单都能到 80 % 以上,有配送员算过,平均每单配送费都在六七元左右。每天平均 3000 单,一个盒马门店一个月就要支出五六十万。
估计是想止一波配送费的血,部分城市的盒马,便强制把运费门槛提高到了 99 元。
 但,这也让习惯了低运费门槛的消费者们,挨了一闷棍。
而且,除了提高免运费门槛,盒马还额外加设了线下特惠价,逼用户到店消费。甚至还有过线下价格,比线上会员价还便宜的情况,这也导致很多会员抱怨盒马不地道。
结果,盒马压根懒得安抚人心,直接挥刀把每年创收五亿多的会员制度全部砍了。
只能说,没人能阻止它,给来线下的家人们谋低价。
可能看到这,你会觉得有点奇怪。盒马不是说要赚钱吗?1 块钱的包装费都要抠搜,产品降价几十块,还有赚头吗?
因为盒马的砍一刀,不只砍在自己身上,也砍了背后的供应商们。
产品方面的降价,主要来自两块地方:一是自有品牌,二是供应商。
在自有品牌方面,盒马决定把占比在3 年内提高到 70% 。所以,我们稍微留心一点,就能发现货柜里的东西,不知道啥时候都印上盒马俩字了。
因为卖自有品牌很爽,利润很高,没有品牌商赚差价。卖多少钱,完全自己说了算。
除此之外,对那些供应商们,盒马也是下了狠手。
先是精简 SKU ( 库存量单位 ),下架 3000 多个产品。
另一方面,对供应商压价。根据茶叶品牌 Chabiubiu 创始人的爆料贴,盒马要他们降一半的价格。
侯毅公开地和供应商们说过: “ 希望你们一次性给我最低价。 ” 
只要愿意给低价,产品有竞争力,那就合作。如果不肯给,再大的牌子也不伺候。如此高压下,导致去年年末就有大量的品牌跳出来说,要跟盒马 “ 断交 ” 。
也难怪侯毅说,有人要封杀他们。如果我是供应商,已经想蹲他楼下,等着暴揍他了。
盒马也知道这样会得罪不少品牌,但没办法,拆分之后,盒马每一步,走的压力都很大。
去年 2 月,蔡崇信在阿里巴巴业绩会上说: “ 我们的资产负债表上依然有一些传统的实体零售业务,这些也不是我们的核心聚焦。如果能够完成退出的话,也是非常合理的。 ” 
 面对不断调整的阿里,盒马必须尽快完成它所谓的 “ 753  ” 大业即 KA ( 大客户 )商品是市场价的七折,自有品牌是市场价的五折,临期商品是市场价的三折
归根结底一句话,用便宜的价格来抢用户,扩规模。
但价格压得越低,那些供货稳定的大牌子,就更懒得陪盒马玩。全靠自营,现在的盒马能力又还不够格。
好在盒马现在在圈子里,还有点号召力。
曾经公开断供的王小卤,转头又和盒马牵上手了。盒马还顺便谈下了百世、玛氏。。。

也不可否认,盒马也依然拥有着一批相当忠实的用户,对很多人来说,盒马是更适合中国人体质的“ 山姆 ”。

他们烧钱烧出来的日鲜蔬菜、肉类、品质在线的甜点,以及快速的配送网络,对于大城市里不好去菜市场的人来说,确实是很方便。

反正差评君还记得,公司附近的盒马刚开业的时候,编辑部不少同事可都是翘班去实地考察的。用同事的原话来形容,第一次去盒马,甚至有种“ 楚雨荨第一次去美特斯邦威 ”的即视感。

当然玩笑归玩笑,盒马确实是不少人对新零售生鲜超市这个概念的启蒙。

但赔钱的生意终是做不长久,只能看盒马接下来,还会祭出什么样的牌吧。

撰文:四大  编辑:江江 & 面线 & 大饼  封面:焕妍

图片、资料来源

知危:盒马勒紧裤腰带:员工被转为临时工,有人含泪签协议、被暂缓IPO上市,但盒马不得不狂飙

chabiubiu:一位女性新消费创业者的艰难求生

第一财经“”盒马为什么得罪会员也要线上线下不同价

市界:盒马连砍了自己三刀

财新:盒马推折扣化变革 CEO侯毅决心告别KA模式

转自: https://mp.weixin.qq.com/s/u99dMf-odSpLqLH86zyOSw

6月15日—17日!2024年上海中考时间公布

2月29日,上海市教委公布《2024年本市高中阶段学校招生工作的若干意见》(以下简称《若干意见》),今年上海中考时间为6月15日-17日。


2024年上海市初中学业水平考试

时间安排


根据《若干意见》,本市高中阶段学校招生以初中学业水平考试(以下简称“学业考试”)语文、数学、外语、道德与法治、历史、体育与健身和综合测试(含物理、化学、跨学科案例分析、物理和化学实验操作)的成绩作为录取的基本依据,总分750分。


2024年学业考试全部安排在标准化考点进行,按照国家教育考试的标准和要求规范考务工作组织实施。回户籍地或居住证登记地址所在区参加中招报名(以下简称“跨区报名”)的学生,在学籍所在区参加学业考试。往届生、返沪生在报名所在区参加学业考试。残疾学生参加考试可申请相应合理便利。学业考试的语文、数学、英语、道德与法治和历史科目以及综合测试笔试实行全市统一网上评卷;其他科目考试评定工作由各区教育局组织实施。


2024年本市中招志愿填报统一在学业考试后、成绩发布前进行。各批次志愿在市级统一平台进行网上填报。学生须在规定时间内登录“上海招考热线”网站进行志愿填报。填报完成后,学生本人及家长(监护人)须进行志愿书面确认。


根据《实施意见》,今年上海高中阶段学校招生录取(以下简称“中招录取”)分三个批次进行,依次为自主招生录取、名额分配综合评价录取、统一招生录取。其中,自主招生录取在学业考试后进行,录取顺序依次为:市实验性示范性高中、市特色普通高中自主招生录取;市级优秀体育学生、艺术骨干学生自主招生录取;国际课程班和中外合作办学高中自主招生录取;中职校自主招生录取。名额分配综合评价录取工作在自主招生录取后进行。名额分配综合评价录取的总分由学业考试总成绩和综合素质评价成绩两部分构成,录取顺序依次为:“名额分配到区”录取;“名额分配到校”录取。统一招生录取工作中,“1至15志愿”招生录取由各区招考机构负责。各区招考机构根据学生学业考试总成绩和志愿,按平行志愿方式,从高分到低分进行录取。“1至15志愿”未被录取的学生,由各区招考机构负责进行征求志愿的填报和录取工作。


市教委要求,市、区招考机构以及各招生学校必须按《若干意见》中“2024年上海市高中阶段学校招生公布公示内容” 适时对外公布有关信息。各区招考机构网站要建立健全中招专栏,加强招生工作信息公开力度。


2024年上海市高中阶段学

招生日程表


文字:符佳

编辑:储咏瑜

* 转载请注明来自浦东发布官方微信


*直击引领区丨将人工智能嵌入全线业务,ABB发布新一轮AI战略

*守好船载危险货物审核关,浦东海事局全力维护辖区水上安全

转自: 浦东发布

从 Flask 切到 FastAPI 后,起飞了!

本文翻译自 Moving from Flask to FastAPI, 作者:Amal Shaji

刚好笔者这几天上手体验 FastAPI,感受到这个框架易用和方便。之前也使用过 Python 中的 Django 和 Flask 作为项目的框架。Django 说实话上手也方便,但是学习起来有点重量级框架的感觉,FastAPI 带给我的直观体验还是很轻便的,本文翻译的这篇文章就会着重介绍 FastAPI 和 Flask 的区别。

Python 是最流行的编程语言之一。从脚本到 API 开发再到机器学习,Python 都有着它自己的足迹。因为 Python 注重开发者的体验和其所能提供的大量工具而大受欢迎。网络框架 Flask 就是这样一个工具,它在机器学习社区中很受欢迎。它也被广泛用于 API开发。但是有一个新的框架正在崛起: FastAPI。与 Flask 不同,FastAPI 是一个 ASGI(Asynchronous Server Gateway Interface 异步服务器网关接口)框架。与 Go 和 NodeJS 一样,FastAPI 是最快的基于 Python 的 Web 框架之一。

本文针对那些有兴趣从 Flask 转移到 FastAPI 的人,比较和对比了 Flask 和 FastAPI 的常见模式。

# FastAPI vs Flask

FastAPI 的构建考虑了以下三个主要问题:

  • 速度
  • 开发者经验
  • 开放标准

你可以把 FastAPI 看作是把 Starlette、Pydantic、OpenAPI 和 JSON Schema 粘合在一起的胶水。

  • 本质上说,FastAPI 使用 Pydantic 进行数据验证,并使用 Starlette 作为工具,使其与 Flask 相比快得惊人,具有与 Node 或 Go 中的高速 Web APIs 相同的性能。
  • Starlette + Uvicorn 提供异步请求能力,这是 Flask 所缺乏的。
  • 有了 Pydantic 以及类型提示,你就可以得到一个具有自动完成功能的良好的编辑体验。你还可以得到数据验证、序列化和反序列化(用于构建一个 API),以及自动化文档(通过 JSON Schema 和 OpenAPI )。

也就是说,Flask 的使用更为广泛,所以它经过了实战检验,并且有更大的社区支持它。由于这两个框架都是用来扩展的,Flask 显然是赢家,因为它有庞大的插件生态系统。

建议:

  • 如果你对上述三个问题有共鸣,厌倦了 Flask 扩展时的大量选择,希望利用异步请求,或者只是想建立一个 RESTful API,请使用 FastAPI。
  • 如果你对 FastAPI 的成熟度不满意,需要用服务器端模板构建一个全栈应用,或者离不开一些社区维护的 Flask 扩展,就可以使用 Flask。

# 开始

 安装

与任何其他 Python 包一样,安装非常简单。

Flask

pip install flask

# or
poetry add flask
pipenv install flask
conda install flask

FastAPI

pip install fastapi uvicorn

# or
poetry add fastapi uvicorn
pipenv install fastapi uvicorn
conda install fastapi uvicorn -c conda-forge

与 Flask 不同,FastAPI 没有内置的开发服务器,因此需要像 Uvicorn 或 Daphne 这样的 ASGI 服务器。

 “Hello World” 应用

Flask

# flask_code.py

from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return {"Hello""World"}

if __name__ == "__main__":
    app.run()

FastAPI

# fastapi_code.py

import uvicorn
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def home():
    return {"Hello""World"}

if __name__ == "__main__":
    uvicorn.run("fastapi_code:app")

reload=True 这样的参数可以被传递到 uvicorn.run() 中,以实现开发时的热重载。

或者,您可以直接从终端启动服务器:

uvicorn run fastapi_code:app

热加载模式:

uvicorn run fastapi_code:app --reload

# 配置

Flask 和 FastAPI 都提供了许多选项来处理不同环境的不同配置。两者都支持以下模式:

  1. 环境变量
  2. 配置文件
  3. 实例文件夹
  4. 类和继承

有关更多信息,请参阅其各自的文档:

  • Flask: https://flask.palletsprojects.com/en/2.0.x/config/
  • FastAPI:https://fastapi.tiangolo.com/advanced/settings/

Flask

import os
from flask import Flask

class Config(object):
    MESSAGE = os.environ.get("MESSAGE")

app = Flask(__name__)
app.config.from_object(Config)

@app.route("/settings")
def get_settings():
    return { "message": app.config["MESSAGE"] }

if __name__ == "__main__":
    app.run()

现在,在你运行服务器之前,设置适当的环境变量:

export MESSAGE="hello, world"

FastAPI

import uvicorn
from fastapi import FastAPI
from pydantic import BaseSettings

class Settings(BaseSettings):
    message: str

settings = Settings()
app = FastAPI()

@app.get("/settings")
def get_settings():
    return { "message": settings.message }

if __name__ == "__main__":
    uvicorn.run("fastapi_code:app")

同样,在运行服务器之前,设置适当的环境变量:

export MESSAGE="hello, world"

# 路由, 模板和视图

 HTTP 方法

Flask

from flask import request

@app.route("/", methods=["GET", "POST"])
def home():
    # handle POST
    if request.method == "POST":
        return {"Hello""POST"}
    # handle GET
    return {"Hello""GET"}

FastAPI

@app.get("/")
def home():
    return {"Hello""GET"}

@app.post("/")
def home_post():
    return {"Hello""POST"}

FastAPI 为每个方法提供单独的装饰器:

@app.get("/")
@app.post("/")
@app.delete("/")
@app.patch("/")

 URL 参数

通过 URL(如 /employee/1 )传递信息以管理状态:

Flask

@app.route("/employee/<int:id>")
def home():
    return {"id": id}

FastAPI

@app.get("/employee/{id}")
def home(id: int):
    return {"id": id}

URL参数的指定类似于一个 f-string 表达式。此外,你还可以利用类型提示。这里,我们在运行时告诉 Pydantic, idint 类型的。在开发中,这也可以帮助完成更好的代码完成度。

 查询参数

与 URL 参数一样,查询参数(如 /employee?department=sales )也可用于管理状态(通常用于过滤或排序):

Flask

from flask import request

@app.route("/employee")
def home():
    department = request.args.get("department")
    return {"department": department}

FastAPI

@app.get("/employee")
def home(department: str):
    return {"department": department}

 模板

Flask

from flask import render_template

@app.route("/")
def home():
    return render_template("index.html")

默认情况下,Flask会在 “templates “文件夹中寻找模板。

FastAPI

你需要安装 Jinja:

pip install jinja2

实现:

from fastapi import Request
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse

app = FastAPI()

templates = Jinja2Templates(directory="templates")

@app.get("/", response_class=HTMLResponse)
def home(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

对于 FastAPI,你需要明确地定义 “模板 “文件夹。然后对于每个响应,需要提供请求上下文。

 静态文件

Flask

默认情况下,Flask 从“static”文件夹中提供静态文件。

FastAPI

在 FastAPI 中,需要为静态文件挂载一个文件夹:

from fastapi.staticfiles import StaticFiles

app = FastAPI()

app.mount("/static", StaticFiles(directory="static"), name="static")

 异步任务

Flask

从 Flask 2.0 开始,您可以使用 async/await 创建异步路由处理程序:

@app.route("/")
async def home():
    result = await some_async_task()
    return result

有关 Flask 中异步视图的更多信息,请查看 Flask 2.0 中的异步一文。

Flask 中的异步也可以通过使用线程(并发)或多处理(并行)或 Celery 或 RQ 等工具来实现:

  1. Asynchronous Tasks with Flask and Celery:https://testdriven.io/blog/flask-and-celery/
  2. Asynchronous Tasks with Flask and Redis Queue:https://testdriven.io/blog/asynchronous-tasks-with-flask-and-redis-queue/

FastAPI

由于 FastAPI 对 asyncio 的原生支持,它极大地简化了异步任务。要使用的话,只需在视图函数中添加 async 关键字:

@app.get("/")
async def home():
    result = await some_async_task()
    return result

FastAPI 还具有后台任务功能,您可以使用它来定义返回响应后要运行的后台任务。这对于不需要在发送回响应之前完成的操作很有用。

from fastapi import BackgroundTasks

def process_file(filename: str):
    # process file :: takes minimum 3 secs (just an example)
    pass

@app.post("/upload/{filename}")
async def upload_and_process(filename: str, background_tasks: BackgroundTasks):
    background_tasks.add_task(process_file, filename)
    return {"message""processing file"}

在这里,响应将被即时发送,而不会让用户等待文件处理完成。

当你需要进行繁重的后台计算时,或者你需要一个任务队列来管理任务(tasks)和工作者(workers)时,你可能想使用Celery 而不是 BackgroundTasks。更多内容请参考 FastAPI 和 Celery 的异步任务:https://testdriven.io/blog/fastapi-and-celery/

 依赖注入

Flask

虽然你可以实现自己的依赖注入解决方案,但 Flask 默认没有真正的一流支持。相反,你需要使用一个外部包,如 flask-injector。

FastAPI

另一方面,FastAPI 具有处理依赖注入的强大解决方案。

例如:

from databases import Database
from fastapi import Depends
from starlette.requests import Request

from db_helpers import get_all_data
def get_db(request: Request):
    return request.app.state._db

@app.get("/data")
def get_data(db: Database = Depends(get_db)):
    return get_all_data(db)

因此,get_db 将获取对在应用程序的启动事件处理程序中创建的数据库连接的引用。 Depends 然后用于向 FastAPI 指示路由“依赖于” get_db。因此,它应该在路由处理程序中的代码之前执行,并且结果应该“注入”到路由本身。

 数据校验

Flask

Flask 没有任何内部数据验证支持。您可以使用功能强大的 Pydantic 包通过 Flask-Pydantic 进行数据验证。

FastAPI

FastAPI 如此强大的原因之一是它支持 Pydantic。

from pydantic import BaseModel

app = FastAPI()

class Request(BaseModel):
    username: str
    password: str

@app.post("/login")
async def login(req: Request):
    if req.username == "testdriven.io" and req.password == "testdriven.io":
        return {"message""success"}
    return {"message""Authentication Failed"}

在这里,我们接受一个模型 Request 的输入。该 payload 必须包含一个用户名和密码。

# correct payload format
✗ curl -X POST 'localhost:8000/login' 
    --header 'Content-Type: application/json' 
    --data-raw '{"username": "testdriven.io","password":"testdriven.io"}'

{"message":"success"}

# incorrect payload format
✗ curl -X POST 'localhost:8000/login' 
    --header 'Content-Type: application/json' 
    --data-raw '{"username": "testdriven.io","passwords":"testdriven.io"}'

{"detail":[{"loc":["body","password"],"msg":"field required","type":"value_error.missing"}]}

注意到这个请求。我们把密码 passwords 作为一个键而不是 password 传递进去。Pydantic 模型会自动告诉用户,password 字段是缺失的。

 序列化和反序列化

Flask

最简单的序列化方法是使用 jsonify:

from flask import jsonify
from data import get_data_as_dict

@app.route("/")
def send_data():
    return jsonify(get_data_as_dict)

对于复杂的对象,Flask 开发者经常使用 Flask-Marshmallow

FastAPI

FastAPI 自动序列化任何返回的字典 dict 。对于更复杂和结构化的数据,使用 Pydantic:

from pydantic import BaseModel

app = FastAPI()

class Request(BaseModel):
    username: str
    email: str
    password: str

class Response(BaseModel):
    username: str
    email: str

@app.post("/login", response_model=Response)
async def login(req: Request):
    if req.username == "testdriven.io" and req.password == "testdriven.io":
        return req
    return {"message""Authentication Failed"}

在这里,我们添加了一个包含三个输入的 Request 模型:用户名、电子邮件和密码。我们还定义了一个仅包含用户名和电子邮件的 Response 模型。输入 Request 模型处理反序列化,而输出 Response 模型处理对象序列化。然后通过 response_model 参数将响应模型传递给装饰器。

现在,如果我们将请求本身作为响应返回,Pydantic 将省略 password ,因为我们定义的响应模型不包含密码字段。

例如:

# output
✗ curl -X POST 'localhost:8000/login' 
    --header 'Content-Type: application/json' 
    --data-raw '{"username":"testdriven.io","email":"admin@testdriven.io","password":"testdriven.io"}'

{"username":"testdriven.io","email":"admin@testdriven.io"}

 中间件

中间件被用来在每个请求被视图功能处理之前应用逻辑。

Flask

class middleware:
    def __init__(self, app) -> None:
        self.app = app

    def __call__(self, environ, start_response):
        start = time.time()
        response = self.app(environ, start_response)
        end = time.time() - start
        print(f"request processed in {end} s")
        return response

app = Flask(__name__)
app.wsgi_app = middleware(app.wsgi_app)

FastAPI

from fastapi import Request

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    print(f"request processed in {process_time} s")
    return response

@app.middleware("http") 装饰器是在 FastAPI 中创建中间件的必备工具。上述中间件计算处理请求所花费的时间。视图函数处理请求后,计算总处理时间并将其作为响应头返回。

# flask output(logs)
request processed in 0.0010077953338623047 s
127.0.0.1 - - [22/Sep/2020 18:56:21"GET / HTTP/1.1" 200 -

# fastapi output(logs)
request processed in 0.0009925365447998047 s
INFO:     127.0.0.1:51123 - "GET / HTTP/1.1" 200 OK

 模块化

随着应用程序的发展,在某些时候你会想把类似的视图、模板、静态文件和模型组合在一起,以帮助把应用程序分解成更小的组件。

Flask

在 Flask 中,蓝图被用来实现模块化:

# blueprints/product/views.py
from flask import Blueprint

product = Blueprint("product", __name__)

@product.route("/product1")
    ...
# main.py

from blueprints.product.views import product

app.register_blueprint(product)

FastAPI

同时,在 FastAPI 中,模块化是通过 APIRouter 实现的:

# routers/product/views.py
from fastapi import APIRouter

product = APIRouter()

@product.get("/product1")
    ...
# main.py

from routers.product.views import product

app.include_router(product)

# 其他特点

 自动文档

Flask

Flask 不会自动创建开箱即用的 API 文档。然而,有几个扩展可以处理这个问题,比如 flask-swagger 和 Flask RESTX,但它们需要额外的设置。

FastAPI

默认情况下,FastAPI 支持 OpenAPI 以及 Swagger UI 和 ReDoc。这意味着每个端点都自动从与端点关联的元数据中记录下来。

所有注册的端点都列在这里

此处列出了所有已注册的端点

替代文档

 管理应用

Flask

Flask 有一个广泛使用的第三方管理包,称为 Flask-Admin,用于快速对您的模型执行 CRUD 操作。

FastAPI

截至目前,有两个流行的 FastAPI 扩展用于此:

  1. FastAPI Admin – 功能性管理面板,提供用于对数据执行 CRUD 操作的用户界面。
  2. SQLAlchemy Admin -FastAPI/Starlette 的管理面板,可与 SQLAlchemy 模型一起使用。

 身份认证

Flask

虽然 Flask 没有原生解决方案,但可以使用多个第三方扩展。

FastAPI

FastAPI 通过 fastapi.security 包原生支持许多安全和身份验证工具。通过几行代码,您可以将基本的 HTTP 身份验证添加到您的应用程序中:

import secrets

from fastapi import Depends, FastAPI, HTTPException, status
from fastapi.security import HTTPBasic, HTTPBasicCredentials

app = FastAPI()

security = HTTPBasic()


def get_current_username(credentials: HTTPBasicCredentials = Depends(security)):
    correct_username = secrets.compare_digest(credentials.username, "stanleyjobson")
    correct_password = secrets.compare_digest(credentials.password, "swordfish")
    if not (correct_username and correct_password):
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED)
    return credentials.username


@app.get("/whoami")
def who_ami_i(username: str = Depends(get_current_username)):
    return {"username": username}

FastAPI 通过 OpenAPI 标准实现 OAuth2 和 OpenID Connect。

查看官方文档中的以下资源以获取更多信息:

  1. Security Intro:https://fastapi.tiangolo.com/tutorial/security/
  2. Advanced Security:https://fastapi.tiangolo.com/advanced/security/

其他资源

  1. Web Authentication Methods Compared:https://testdriven.io/blog/web-authentication-methods/
  2. Adding Social Authentication to Flask:https://testdriven.io/blog/flask-social-auth/
  3. Session-based Auth with Flask for Single Page Apps:https://testdriven.io/blog/flask-spa-auth/
  4. Securing FastAPI with JWT Token-based Authentication:https://testdriven.io/blog/fastapi-jwt-auth/

 CORS

CORS(跨源资源共享)中间件检查请求是否来自允许的来源。如果是,则将请求传递给下一个中间件或视图函数。如果不是,它会拒绝请求,并将错误响应发送回调用者。

Flask Flask 需要一个名为 Flask-CORS 的外部包来支持 CORS:

pip install flask-cors

基本实现:

from flask_cors import CORS

app = Flask(__name__)

CORS(app)

FastAPI

FastAPI 原生支持 CORS:

from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = ["*"]

app.add_middleware(CORSMiddleware, allow_origins=origins)

# 测试

Flask

import pytest
from flask import Flask

app = Flask(__name__)

@app.route("/")
def home():
    return {"message""OK"}

def test_hello():
    res = app.test_client().get("/")

    assert res.status_code == 200
    assert res.data == b'{"message":"OK"}n'

FastAPI

from fastapi import FastAPI
from fastapi.testclient import TestClient

app = FastAPI()

@app.get("/")
async def home():
    return {"message""OK"}

client = TestClient(app)

def test_home():
    res = client.get("/")

    assert res.status_code == 200
    assert res.json() == {"message""OK"}

FastAPI 提供了一个 TestClient。有了它,你可以直接用 FastAPI 运行 pytest。有关更多信息,请查看官方文档中的测试指南。

# 部署

 生产服务器

Flask

Flask 默认运行开发 WSGI(Web 服务器网关接口)应用程序服务器。对于生产环境,您需要使用生产级 WSGI 应用服务器,例如 Gunicorn、uWSGI 或 mod_wsgi

安装 Gunicorn:

pip install gunicorn

启动服务:

# main.py
# app = Flask(__name__)

gunicorn main:app

FastAPI

由于 FastAPI 没有开发服务器,您将使用 Uvicorn(或 Daphne)进行开发和生产。

安装 Uvicorn:

pip install uvicorn

启动服务:

python
# main.py
# app = FastAPI()

uvicorn main:app

您可能希望使用 Gunicorn 来管理 Uvicorn,以便同时利用并发性(通过 Uvicorn)和并行性(通过 Gunicorn worker):

# main.py
# app = FastAPI()

gunicorn -w 3 -k uvicorn.workers.UvicornWorker main:app

 Docker

Flask

FROM python3.10-slim

WORKDIR /app

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY . .

EXPOSE 5000

CMD ["gunicorn""main:app"]

这是 Flask 最简单的 Dockerfile 之一。要了解如何针对生产对其进行全面配置,请查看使用 Postgres、Gunicorn 和 Nginx 教程对 Flask 进行 Docker 化。

FastAPI

sql
FROM python3.10-slim

WORKDIR /app

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["uvicorn""main:app"]

同样,这是一个非常简单的配置。 FastAPI 作者提供了几个生产就绪的 Dockerfile。有关更多信息,请查看官方 FastAPI 文档以及 Dockerizing FastAPI with Postgres、Uvicorn 和 Traefik 教程。

# 总结

退一步讲,Django 和 Flask 是两个最流行的基于 Python 的网络框架(FastAPI 是第三大流行框架)。不过它们(Django 和 Flask)的理念非常不同。Flask 比 Django 的优势在于 Flask 是一个微框架。程序结构由程序员自己决定,不强制执行。开发者可以在他们认为合适的时候添加第三方扩展来改进他们的代码。也就是说,通常情况下,随着代码库的增长,需要一些几乎所有网络应用都需要的通用功能。这些功能与框架的紧密结合,使得终端开发者需要自己创建和维护的代码大大减少。

本文中的代码实例也表达了同样的意思。换句话说,FastAPI 包括许多必要的功能。它还遵循严格的标准,使你的代码可以生产并更容易维护。FastAPI 的文档也非常完善。

虽然 FastAPI 可能不像 Flask 那样久经考验,但越来越多的开发人员正在转向它来提供机器学习模型或开发 RESTful API。切换到 FastAPI 是一个不错的选择。

# 官方文档

  • FastAPI:https://fastapi.tiangolo.com/
  • Flask:https://flask.palletsprojects.com/en/2.0.x/

# 其他资源

  • Porting Flask to FastAPI for ML Model Serving:https://www.pluralsight.com/tech-blog/porting-flask-to-fastapi-for-ml-model-serving/
  • Why we switched from Flask to FastAPI for production machine learning:https://towardsdatascience.com/why-we-switched-from-flask-to-fastapi-for-production-machine-learning-765aab9b3679
  • Awesome Flask:https://github.com/mjhea0/awesome-flask
  • Awesome FastAPI:https://github.com/mjhea0/awesome-fastapi

作者:宇宙之一粟
链接:https://juejin.cn/post/7219225476706140218

为什么宗庆后是中国本土企业家的极致代表

  凤凰网原创  宗庆后幸运地搭上了时代的列车进入了头等舱。悼念宗庆后,当然不是因为他能进入头等舱,而是希望中国这列火车,在更加理性、包容、公平的市场经济环境中,继续保持快车道。

作者|刘远举
财经专栏作家、多家智库研究员
2月25日,娃哈哈官方微博发布讣告,娃哈哈集团创始人、董事长宗庆后,因病医治无效逝世,享年79岁。这个消息并不突然,早在此前几天,就陆续传出宗庆后因肺癌进入ICU的消息。
盖棺未必定论,但商业成就是清晰的。现在杭州娃哈哈集团有限公司是国内领军型饮料企业,位居中国企业500强、中国制造业500强、中国民企500强前列,是中国最具影响力的民营企业之一。宗庆后本人,也曾三次问鼎中国首富。
从另一个角度,宗庆后也做到了当下一个中国民营企业家的极致。
在娃哈哈官方微博发布的落款却是治丧委员会的讣告中,宗庆后拥有一系列荣耀的头衔:中国共产党党员,全国劳动模范,全国五一劳动奖章获得者,优秀中国特色社会主义事业建设者,改革开放40年百名杰出民营企业家,第十、十一、十二届全国人大代表,中国共产党浙江省第十二、十三、十四届代表大会代表。最后,才是娃哈哈集团创始人、董事长。

原始积累:超越时代的敏锐
1945年出生的宗庆后,用现在的话说,他人生一开始就拿到了一手烂牌。因为父亲是南京政府职员,这种伪职员的阶级成分,让他无法报考师范学校。此后他辍学,开始自谋生路,在杭州走街串巷卖爆炒米和煮红薯。
年轻人的就业不好了,那就去广大天地接受贫下中农的再教育。1963年,没有多少知识的宗庆后,18岁时也成了知识青年,开始“上山下乡”。他先去了农场,挖沟修坝、拉土堆石,又去了茶场,种茶、插秧、养猪、杀猪。
就这样一晃15年,他度过了,或者说荒废了,自己的青春和青年时期。如果老套的写法,在这里一定会加上:吃苦磨炼人——在这段时期,他积累了自己最宝贵的财富——苦难,甚至宗庆后自己也会这么说。但无论如何,他和任何一个人,都不会希望自己的子女再吃15年这样的苦,也不会希望中国再出现这样的弯路。
在1978年,各种新气象暗流涌动,不时突破水面,一个小小的水泡在水面上破裂开来,形成一圈一圈的涟漪。云南五万知青,惊天一跪请愿,引发云南知青大返城事件。远在西南边陲的水泡,也影响到一个浙江青年;时代机器中的个人命运的小小齿轮,也开始旋转。就在这一年,33岁的宗庆后回杭州,顶替母亲在校办工厂做供销员。
1986年,农村早已施行很久的承包制度,开始进入到城市,进入到工业,开始“推行多种形式的经营承包责任制,给经营者以充分的经营自主权”。这十年间,宗庆后一直主要干的是供销员,人做自己擅长的事,就会顺风顺水。顺着这股子劲头,1987年,宗庆后借来14万元,承包了连年亏损的校办企业经销部,开始了自己的创业人生。
这一年,宗庆后已经41岁了。但他人生的青春,才刚刚拉开序幕。
其实,那还是一个乍暖还寒的年代。就在这一年,著名的傻子瓜子年广九被立案审查,雇工8人算不算剥削,还是那时的时代热议。比起现在B站上的“你工人阶级爷爷来了”“民营经济应该离场”,有过之而无不及。
现在再也没人回到这样一个问题:当年的宗庆后,到底是以中国第一代企业家对政策的敏感性和精确预测,还是以中国底层老百姓的无知而无畏,让他敢于逆势而上,在严峻的民营经济形势中,开始自己的创业。不过,这并不重要了,时代就是这样,用无数人的人生作为自己的铺路石。不同的是,有些石头,最后会发出宝石的光芒,在道路上熠熠生辉,为时代照亮前路。
初富的中国人,在鸡鸭鱼肉之外,开始追求健康,各种口服液层出不穷。宗庆后最初代理了一款“中国花粉口服液”,后来又为其做代工。发现这个市场利润丰厚后,1988年在浙江大学医学营养系主任朱寿民教授的帮助下,宗庆后开发出自己的第一个产品——娃哈哈儿童营养液,创立了杭州娃哈哈营养食品厂。其实,现在来看,成分无非是补锌、补铁,加点中药,要说有实质性效果,其实未必有多少。

宗庆后是懂消费者焦虑的。就在产品即将面世之际,宗庆后却又委托科研机构对3006名小学生进行了一次调查。结果发现,有1336名小学生患有程度不同的营养不良症:缺锌、缺钙、缺铁等营养元素的,竟占到了44.4%。在当时,这是奇怪的,是在花冤枉钱。但在现在看来,其实是基本操作了——用权威机构自带传播的数据,直击焦虑,为产品造势。
对于那时来说,却针对了时代痛点。富裕起来的中国人,希望自己孩子吃得越多越好。而独生子女政策的实施,又形成了一代“小皇帝”。娃哈哈口服液,满足了让小皇帝吃饭的心理焦虑。“喝了娃哈哈,吃饭就是香”的直白广告语,直击家长心智。娃哈哈营养液迅速打开了市场。3年销售过亿,公司完成了初步的原始积累。
这种超越时代的敏锐,一直伴随娃哈哈的整个发展过程。

合资与改制:恩怨背后的中西之争
1994年,娃哈哈积极响应国务院对口支援三峡库区移民工作的号召,投身西部开发,以“移民任务与移民经费总承包”的思路,兼并了涪陵地区受淹的3家特困企业,建立娃哈哈第一家省外分公司涪陵公司。在响应号召的过程中,娃哈哈完成了扩张。
在急速的发展中,娃哈哈集团开始遇到资金、技术的两重障碍。90年代末期,全球化浪潮初现,各国优势商业要素开始在全球范围内配置。这个时候,娃哈哈遇到了急于在中国发展的达能。达能集团,来头不小:1989年时,已经是成为世界第六大、欧洲第三大食品集团,旗下拥有依云、多美滋等多个国际一线品牌。
达能看重娃哈哈的渠道,娃哈哈需要达能的资金和技术,双方一拍即合。1996年,达能联合香港百富勤共同出资4500万美元,与娃哈哈成立了5家合资公司。
意外,商业社会的毫不意外。1997年,亚洲金融风暴来袭,香港百富勤将新加坡金加投资公司30%的股份卖给达能集团。此时,“达娃”合资公司的股权结构变更为达能集团持股51%、娃哈哈集团持股39%、美食城持股10%。合作的天平,已经开始失衡。
虽然祸端已经埋下,但任何婚姻一开始都是喜乐的。“达娃”合资公司先后从美国、德国、日本、意大利、加拿大等发达国家引进了大量的国际先进生产技术,完成了对生产线的升级改造,借势提升了品牌实力,娃哈哈集团再次步入高速发展的快车道。
1998年5月,娃哈哈推出碳酸饮料“非常可乐”,意在挑战可口可乐和百事可乐,凭借的是渠道的优势。2003年5月“非典”疫情结束后,宗庆后抢在竞争对手之前,将大批饮料送到零售终端,使销售实现了16%的年增长,公司营业收入突破100亿元大关。
对宗庆后而言,一边是合资,另一边是改制;合资关乎发展,而改制关系到身家性命。在2000年的改制中,宗及员工从政府手中买回了娃哈哈集团55%的股份,娃哈哈实现“全员持股”。其中,宗庆后占股30%,高级管理层5%,员工20%。近46%的股份,由杭州市上城区国有资产管理有限公司拥有。相对清晰的股权渊源,能让宗庆后在后来能够坐看风云。
2006年4月,达能与娃哈哈矛盾公开化。“达娃之争”,被称为改革开放30年来影响最大的国际商战,诉讼长达三年、遍及全球,还涉及到宗庆后家人。

在中国领导人和法国总统萨科齐的干预下,以更高层面看待此事,达能和娃哈哈发布联合公告,双方同意结和解。最终,2009年9月30日,达能与娃哈哈“友好分手”,终止合资关系,达能将其在各家合资公司中51%的股权出售给娃哈哈,作价3亿欧元,大大低于达能最早提出的12亿欧元。
关于这场争执的解释,至今仍然有众说纷纭。有人说是娃哈哈缺乏契约意识,也有人说达能搞双重标准。这很正常,合同条约、具体情况,各有理解,利益争执中自然是各执一词。
这些原因中,对中国社会的不同看法,以及因之而产生的战略分歧,当是一个很重要的原因。娃哈哈集团希望通过参与西部大开发、对口支援革命老区、国家贫困区等项目建设,完善企业在全国的战略布局,在提升产能的同时树立良好的企业形象。但达能集团予以拒绝,认为这些地区消费潜力低,预期投资回报差。
1999年,宗庆后继续西进北上,决定由职工集资持股成立的公司出面,建立一批与达能没有关系的公司。到2006年,总资产达56亿元,当年利润10.4亿元。这也成为达能指控宗庆后损害合资公司利益的证据。
宗庆后与外国企业家的战略差异,背后是对中国社会的深刻认识与娴熟适应。他曾回顾说:“合资之后,达能曾向娃哈哈派驻了一个搞市场策划的、一个搞技术的,都被我赶走了。因为我觉得他们完全不懂中国市场。”这意味着,某种程度上,和平分手,已经是达能能得到的最好的,或许也是唯一的解决方案。
1996年2月29日,杭州娃哈哈公司与达能签署《商标转让协议》,将“娃哈哈”商标转让给达娃合资公司,但当时国家商标局对此未予核准。此后,达娃公司以《商标使用许可合同》为凭使用娃哈哈商标。国家商标局阻拦在此后的纷争中,救下了娃哈哈。多年之后,当另一位杭州人也因为监管被诟病没有契约意识时,他或许会想到当年的这一幕。
回顾宗庆后的一生,大致上会认为他是一个制造业企业家,这种认知大致上是对的。也正因为是制造业、实体经济企业家,宗庆后在反资本的民间大潮中,能够免于资本家的指控。

哀悼之外:希望时代列车继续保持快车道
不过,仅仅从制造来认识宗庆后是不全面的。
由于长期历史传统和计划经济经历,中国人对工业、经济发展的理解,停留在“造出东西”。造出东西,才是经济发展,才是实体经济。但宗庆后的娃哈哈纯净水,可以告诉人们,市场经济并非简单地“造出东西”。
某种程度上,娃哈哈纯净水的故事,才是宗庆后真正的底色。
现在很多科研实验,都用娃哈哈当做纯水来源,并在论文中标出来,所以现在的论文数据库中,能搜索到大量的娃哈哈。并不是所有的纯水,都能达到这种程度。把一个产品做到如此程度,需要作为企业家的宗庆后,依靠市场,去调动资源,在每个环节,从灌装线、到瓶子、瓶盖,从物流到营销,都做到极致,精益求精。这背后是企业家的殚精竭虑,是多年的坚守和努力。
这当中,制造本身纵然是基础,但营销、市场不可或缺,甚至更为重要。宗庆后靠的是自己独创的“宗氏联销体模式”,即代理商交纳一定金额的保证金,承诺一定数量的年度销量。作为回报,厂商把该区域的商品代理权交给该经销商,并且支付超出银行“数倍”的保证金利息,将娃哈哈的自身利益与经销商的利益捆绑在一起。通过这种像毛细血管一样深入全国各地的销售网络,娃哈哈的产品深入中国大街小巷,公司新品一周内铺遍全国。
正是在强大的制造的基础上,再加上这个网络,宗庆后才能让一瓶娃哈哈纯净水,质量高而稳定,却又价格低廉。资深媒体人秦朔曾评价:“在打造市场方面,宗庆后代表了中国本土企业家的最高成就,他运作快消品的眼光、推广和营销能力更是经典。”
2005年,娃哈哈推出“营养快线”。仅仅一年时间,营养快线就实现了400%以上的增长,销售收入26个亿。显然,这个业绩,离不开这个销售网络。
从这个意义上讲,宗庆后一辈子所做的,并不是计划经济意义下的制造业,而是市场经济意义下的制造业。

2023年12月,已经停办了三年的娃哈哈全国销售工作会议再次举办。上万名经销商,涌进杭州的运河公园体育馆。这场大会上,宗馥莉发表讲话、部署战略,已经接替了父亲往日的角色。后继有人,宗老先生也可没有牵挂。
但,没有近虑就或有远忧。宗庆后最被诟病的,是他的“专制”“独裁”。对此,他并不否认。他曾坦然表示:娃哈哈的企业文化是“家文化”,忠诚和团结是基本的道德要求。这当然会对企业造成一定的损害。
曾经成功的非常可乐,终究是没落了。2002年5月,娃哈哈曾投资数亿元打造童装品牌,后来宗庆后也承认决策失误。
在2014年一场峰会上,宗庆后公开批评电子商务对实体经济产生了负面影响,曾引起非议。但2017年,与阿里巴巴牵手共同推出了共享服务信用亭,在2018年12月上线“哈宝游乐园”试水社交电商,2019年后进一步在抖音、微信、微博等平台进行产品推广。2020年3月24日,杭州娃哈哈电子商务有限公司成立;4月2日,娃哈哈宏振跨境电子商务有限公司成立。这些努力,都悄无声息。
更重要的是,在00后整顿职场的今天,在市场瞬息万变的今天,“家文化”能否适应今后的时代,这需要后继者去回答。
宗庆后的一生,有着浓郁的时代色彩,也是那一代人的缩影,当然,更浓烈,更耀眼。他是一个超越时代的人,同时,又是一个善于适应时代的人。某种程度上,这是中国诸多成功企业家的共同特质。宗庆后生于苦难之中,又幸运地搭上了时代的列车,通过自身努力进入了头等舱。
我们悼念宗庆后,当然不是因为他能进入头等舱,而是希望中国这列火车,在更加理性、包容、公平的市场经济环境中,继续保持快车道。

本文系凤凰网评论部特约原创稿件,仅代表作者立场。

主编|萧轶‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

转自: 风声OPINION https://mp.weixin.qq.com/s/a5HaMkRaTPmavWjiZAJeeA