Tyrion是一个基于Python实现的支持多个WEB框架的Form表单验证组件,其完美的支持Tornado、Django、Flask、Bottle Web框架。Tyrion主要有两大重要动能:

  • 表单验证
  • 生成HTML标签
  • 保留上次提交内容

对于表单验证,告别书写重复的正则表达式对用户提交的数据进行验证的工作,从此解放双手,跟着我左手右手一个慢动作...

对于生成HTML标签,不在人工书写html标签,让Tyrion帮你自动创建...

对于保留上次提交内容,由于默认表单提交后页面刷新,原来输入的内容会清空,Tyrion可以保留上次提交内容。

github:https://github.com/WuPeiqi/Tyrion

使用文档

1、下载安装

pip install PyTyrion 

github: https://github.com/WuPeiqi/Tyrion

2、配置WEB框架种类

由于Tyrion同时支持Tornado、Django、Flask、Bottle多个WEB框架,所有在使用前需要进行指定。

        import TyrionTyrion.setup('tornado') # setup的参数有:tornado(默认)、django、bottle、flask

3、创建Form类

Form类用于提供验证规则、插件属性、错误信息等

    from Tyrion.Forms import Formfrom Tyrion.Fields import StringFieldfrom Tyrion.Fields import EmailFieldclass LoginForm(Form):username = StringField(error={'required': '用户名不能为空'})password = StringField(error={'required': '密码不能为空'})email = EmailField(error={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'})

4、验证用户请求

前端HTML代码:

        <form method="POST" action="/login.html"><div><input type="text" name="username"></div><div><input type="text" name="password"></div><div><input type="text" name="email"></div><input type="submit" value="提交"></form>

用户提交数据时,在后台书写如下代码即可实现用户请求数据验证(Tornado示例):

        class LoginHandler(tornado.web.RequestHandler):def get(self, *args, **kwargs):self.render('login.html')def post(self, *args, **kwargs):form = LoginForm(self)###### 检查用户输入是否合法 ######if form.is_valid():###### 如果不合法,则输出错误信息 ######print(form.error_dict)else:###### 如果合法,则输出用户输入的内容 ######print(form.value_dict)self.render('login.html')

示例01:源码下载(含Tornado、Django、Flask、Bottle)

5、验证用户请求 && 生成HTML标签 && 保留上次输入内容 && 错误提示

Tyrion不仅可以验证用户请求,还可以生成自动创建HTML标签并且可以保留用户上次输入的内容。在HTML模板中调用Form类对象的字段即可,如(Tornado示例):

        from Tyrion.Forms import Formfrom Tyrion.Fields import StringFieldfrom Tyrion.Fields import EmailFieldclass LoginForm(Form):username = StringField(error={'required': '用户名不能为空'})password = StringField(error={'required': '密码不能为空'})email = EmailField(error={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'})

Form类

        class LoginHandler(tornado.web.RequestHandler):def get(self, *args, **kwargs):form = LoginForm(self)self.render('login.html', form=form)def post(self, *args, **kwargs):form = LoginForm(self)print(form.is_valid())print(form.error_dict)print(form.value_dict)self.render('login.html', form=form)

处理请求(Tornado)

        <form method="post" action="/login.html"><div><!-- Form创建的标签 -->{% raw form.username %}<!-- 错误信息 --><span>{{form.error_dict.get('username',"")}}</span></div><div>{% raw form.password %}<span>{{form.error_dict.get('password',"")}}</span></div><div>{% raw form.email %}<span>{{form.error_dict.get('email',"")}}</span></div><input type="submit" value="提交"/></form>

HTML模板login.html

注意: HTML模板中的转义

示例02:源码下载(含有Tornado、Django、Flask、Bottle)

6、Form字段类型

Form的字段用于指定从请求中获取的数据类型以及格式,以此来验证用户输入的内容。

        from Tyrion.Forms import Formfrom Tyrion.Fields import StringFieldfrom Tyrion.Fields import EmailFieldclass LoginForm(Form):username = StringField(error={'required': '用户名不能为空'})password = StringField(error={'required': '密码不能为空'})email = EmailField(error={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'})

以上代码表示此Form类可以用于验证用户输入的内容,并且 username和password必须不能为空,email必须不能为空并且必须是邮箱格式。

目前支持所有字段:

StringField"""要求必须是字符串,即:正则^.*$参数:required    布尔值,是否允许为空max_length  整数,限制用户输入内容最大长度min_length  整数,限制用户输入内容最小长度error       字典,自定义错误提示,如:{'required': '值为空时的错误提示','invalid': '格式错误时的错误提示','max_length': '最大长度为10','min_length': '最小长度为1',}widget      定制生成的HTML插件(默认InputText)"""EmailField"""要求必须是邮箱格式的字符串参数:required    布尔值,是否允许为空max_length  整数,限制用户输入内容最大长度min_length  整数,限制用户输入内容最小长度error       字典,自定义错误提示,如:{'required': '值为空时的错误提示','invalid': '格式错误时的错误提示','max_length': '最大长度为10','min_length': '最小长度为1',}widget      定制生成的HTML插件(默认InputText)"""IPField"""要求必须是IP格式参数:required    布尔值,是否允许为空max_length  整数,限制用户输入内容最大长度min_length  整数,限制用户输入内容最小长度error       字典,自定义错误提示,如:{'required': '值为空时的错误提示','invalid': '格式错误时的错误提示','max_length': '最大长度为10','min_length': '最小长度为1',}widget      定制生成的HTML插件(默认InputText)"""IntegerField"""要求必须整数格式参数:required    布尔值,是否允许为空max_value   整数,限制用户输入数字最大值min_value   整数,限制用户输入数字最小值error       字典,自定义错误提示,如:{'required': '值为空时的错误提示','invalid': '格式错误时的错误提示','max_value': '最大值为10','max_value': '最小值度为1',}widget      定制生成的HTML插件(默认InputText)"""FloatField"""要求必须小数格式参数:required    布尔值,是否允许为空max_value   整数,限制用户输入数字最大值min_value   整数,限制用户输入数字最小值error       字典,自定义错误提示,如:{'required': '值为空时的错误提示','invalid': '格式错误时的错误提示','max_value': '最大值为10','max_value': '最小值度为1',}widget      定制生成的HTML插件(默认InputText)"""StringListField"""用于获取请求中的多个值,且保证每一个元素是字符串,即:正则^.*$如:checkbox或selct多选时,会提交多个值,用此字段可以将用户提交的值保存至列表参数:required         布尔值,是否允许为空ele_max_length   整数,限制用户输入的每个元素内容最大长度ele_min_length   整数,限制用户输入的每个元素内容最小长度error            字典,自定义错误提示,如:{'required': '值为空时的错误提示','element': '列表中的元素必须是字符串','ele_max_length': '最大长度为10','ele_min_length': '最小长度为1',}widget           定制生成的HTML插件(默认InputMultiCheckBox,即:checkbox)"""IntegerListField"""用于获取请求中的多个值,且保证每一个元素是整数如:checkbox或selct多选时,会提交多个值,用此字段可以将用户提交的值保存至列表参数:required         布尔值,是否允许为空ele_max_value   整数,限制用户输入的每个元素内容最大长度ele_min_value   整数,限制用户输入的每个元素内容最小长度error            字典,自定义错误提示,如:{'required': '值为空时的错误提示','element': '列表中的元素必须是数字','ele_max_value': '最大值为x','ele_min_value': '最小值为x',}widget           定制生成的HTML插件(默认InputMultiCheckBox,即:checkbox)"""

View Code

7、Form字段widget参数:HTML插件

HTML插件用于指定当前字段在生成HTML时表现的种类和属性,通过指定此参数从而实现定制页面上生成的HTML标签

            from Tyrion.Forms import Formfrom Tyrion.Fields import StringFieldfrom Tyrion.Fields import EmailFieldfrom Tyrion.Widget import InputPasswordclass LoginForm(Form):password = StringField(error={'required': '密码不能为空'},widget=InputPassword())

上述LoginForm的password字段要求用户输入必须是字符串类型,并且指定生成HTML标签时会创建为<input type='password' > 标签

目前支持所有插件:

    InputText"""设置Form对应字段在HTML中生成input type='text' 标签参数:attr    字典,指定生成标签的属性,如: attr = {'class': 'c1', 'placeholder': 'username'}"""InputEmail"""设置Form对应字段在HTML中生成input type='email' 标签参数:attr    字典,指定生成标签的属性,如: attr = {'class': 'c1', 'placeholder': 'username'}"""InputPassword"""设置Form对应字段在HTML中生成input type='password' 标签参数:attr    字典,指定生成标签的属性,如: attr = {'class': 'c1', 'placeholder': 'username'}"""TextArea"""设置Form对应字段在HTML中生成 textarea 标签参数:attr    字典,指定生成标签的属性,如: attr = {'class': 'c1'}value   字符串,用于设置textarea标签中默认显示的内容"""InputRadio"""设置Form对应字段在HTML中生成一系列 input type='radio' 标签(选择时互斥)参数:attr                字典,生成的HTML属性,如:{'class': 'c1'}text_value_list     列表,生成的多个radio标签的内容和值,如:[{'value':1, 'text': '男'},{'value':2, 'text': '女'},]checked_value       整数或字符串,默认被选中的标签的value的值示例:from Tyrion.Forms import Formfrom Tyrion.Fields import IntegerFieldfrom Tyrion.Widget import InputRadioclass LoginForm(Form):favor = IntegerField(error={'required': '爱好不能为空'},widget=InputRadio(attr={'class': 'c1'},text_value_list=[{'value': 1, 'text': '男'},{'value': 2, 'text': '女'}, ],checked_value=2))上述favor字段生成的HTML标签为:<div><span><input class='c1' type="radio" name="gender" value="1"></span><span>男</span></div><div><span><input class='c1' type="radio" name="gender" value="2" checked='checked'></span><span>女</span></div>"""InputSingleCheckBox"""设置Form对应字段在HTML中生成 input type='checkbox' 标签参数:attr    字典,指定生成标签的属性,如: attr = {'class': 'c1'}"""InputMultiCheckBox"""设置Form对应字段在HTML中生成一系列 input type='checkbox' 标签参数:attr                字典,指定生成标签的属性,如: attr = {'class': 'c1'}text_value_list     列表,生成的多个checkbox标签的内容和值,如:[{'value':1, 'text': '篮球'},{'value':2, 'text': '足球'},{'value':3, 'text': '乒乓球'},{'value':4, 'text': '羽毛球'},]checked_value_list  列表,默认选中的标签对应的value, 如:[1,3]"""SingleSelect"""设置Form对应字段在HTML中生成 单选select 标签参数:attr                字典,指定生成标签的属性,如: attr = {'class': 'c1'}text_value_list     列表,用于指定select标签中的option,如:[{'value':1, 'text': '北京'},{'value':2, 'text': '上海'},{'value':3, 'text': '广州'},{'value':4, 'text': '重庆'},]selected_value      数字或字符串,默认被选中选项对应的值,如: 3"""MultiSelect"""设置Form对应字段在HTML中生成 多选select 标签参数:attr                字典,指定生成标签的属性,如: attr = {'class': 'c1'}text_value_list     列表,用于指定select标签中的option,如:[{'value':1, 'text': '篮球'},{'value':2, 'text': '足球'},{'value':3, 'text': '乒乓球'},{'value':4, 'text': '羽毛球'},]selected_value_list 列表,默认被选中选项对应的值,如:[2,3,4]"""

View Code

8、动态初始化默认值

由于Form可以用于生成HTML标签,如果想要在创建标签的同时再为其设置默认值有两种方式:

  • 静态,在插件参数中指定
  • 动态,调用Form对象的 init_field_value 方法来指定

class InitValueForm(Form):username = StringField(error={'required': '用户名不能为空'})age = IntegerField(max_value=500,min_value=0,error={'required': '年龄不能为空','invalid': '年龄必须为数字','min_value': '年龄不能小于0','max_value': '年龄不能大于500'})city = IntegerField(error={'required': '年龄不能为空', 'invalid': '年龄必须为数字'},widget=SingleSelect(text_value_list=[{'value': 1, 'text': '上海'},{'value': 2, 'text': '北京'},{'value': 3, 'text': '广州'}]))gender = IntegerField(error={'required': '请选择性别','invalid': '性别必须为数字'},widget=InputRadio(text_value_list=[{'value': 1, 'text': '男', },{'value': 2, 'text': '女', }],checked_value=2))protocol = IntegerField(error={'required': '请选择协议', 'invalid': '协议格式错误'},widget=InputSingleCheckBox(attr={'value': 1}))favor_int_val = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=InputMultiCheckBox(text_value_list=[{'value': 1, 'text': '篮球', },{'value': 2, 'text': '足球', },{'value': 3, 'text': '乒乓球', },{'value': 4, 'text': '羽毛球'}, ]))favor_str_val = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=InputMultiCheckBox(text_value_list=[{'value': '1', 'text': '篮球', },{'value': '2', 'text': '足球', },{'value': '3', 'text': '乒乓球', },{'value': '4', 'text': '羽毛球'}, ]))select_str_val = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=MultiSelect(text_value_list=[{'value': '1', 'text': '篮球', },{'value': '2', 'text': '足球', },{'value': '3', 'text': '乒乓球', },{'value': '4', 'text': '羽毛球'}, ]))select_int_val = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=MultiSelect(text_value_list=[{'value': 1, 'text': '篮球', },{'value': 2, 'text': '足球', },{'value': 3, 'text': '乒乓球', },{'value': 4, 'text': '羽毛球'}, ]))

动态初始值 - Form类

class InitValueHandler(tornado.web.RequestHandler):def get(self, *args, **kwargs):form = InitValueForm(self)init_dict = {'username': 'seven','age': 18,'city': 2,'gender': 2,'protocol': 1,'favor_int_val': [1, 3],'favor_str_val': ['1', '3'],'select_int_val': [1, 3],'select_str_val': ['1', '3']}# 初始化操作,设置Form类中默认值以及默认选项
                form.init_field_value(init_dict)self.render('init_value.html', form=form)

动态初始值 - 处理请求的Handler(Tornado)

9、更多示例

示例源码下载:猛击这里

a. 基本使用

    class RegisterForm(Form):username = StringField(max_length=32,min_length=6,error={'required': '用户名不能为空','min_length': '用户名不能少于6位','max_length': '用户名不能超过32位'})password = StringField(max_length=32,min_length=6,error={'required': '密码不能为空'},widget=InputPassword())gender = IntegerField(error={'required': '请选择性别','invalid': '性别必须为数字'},widget=InputRadio(text_value_list=[{'value': 1, 'text': '男', },{'value': 2, 'text': '女', }],checked_value=2))age = IntegerField(max_value=500,min_value=0,error={'required': '年龄不能为空','invalid': '年龄必须为数字','min_value': '年龄不能小于0','max_value': '年龄不能大于500'})email = EmailField(error={'required': '邮箱不能为空','invalid': '邮箱格式错误'})city = IntegerField(error={'required': '城市选项不能为空', 'invalid': '城市选项必须为数字'},widget=SingleSelect(text_value_list=[{'value': 1, 'text': '上海'},{'value': 2, 'text': '北京'},{'value': 3, 'text': '广州'}]))protocol = IntegerField(error={'required': '请选择协议', 'invalid': '协议格式错误'},widget=InputSingleCheckBox(attr={'value': 1}))memo = StringField(required=False,max_length=150,error={'invalid': '备注格式错误', 'max_length': '备注最大长度为150字'},widget=TextArea())

b. 多选checkbox

    class MultiCheckBoxForm(Form):favor_str_val = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=InputMultiCheckBox(text_value_list=[{'value': '1', 'text': '篮球', },{'value': '2', 'text': '足球', },{'value': '3', 'text': '乒乓球', },{'value': '4', 'text': '羽毛球'}, ]))favor_str_val_default = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=InputMultiCheckBox(text_value_list=[{'value': '1', 'text': '篮球', },{'value': '2', 'text': '足球', },{'value': '3', 'text': '乒乓球', },{'value': '4', 'text': '羽毛球'}, ],checked_value_list=['1', '4']))favor_int_val = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=InputMultiCheckBox(text_value_list=[{'value': 1, 'text': '篮球', },{'value': 2, 'text': '足球', },{'value': 3, 'text': '乒乓球', },{'value': 4, 'text': '羽毛球'}, ]))favor_int_val_default = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=InputMultiCheckBox(text_value_list=[{'value': 1, 'text': '篮球', },{'value': 2, 'text': '足球', },{'value': 3, 'text': '乒乓球', },{'value': 4, 'text': '羽毛球'}, ],checked_value_list=[2, ]))

c、多选select

    class MultiSelectForm(Form):select_str_val = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=MultiSelect(text_value_list=[{'value': '1', 'text': '篮球', },{'value': '2', 'text': '足球', },{'value': '3', 'text': '乒乓球', },{'value': '4', 'text': '羽毛球'}, ]))select_str_val_default = StringListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=MultiSelect(text_value_list=[{'value': '1', 'text': '篮球', },{'value': '2', 'text': '足球', },{'value': '3', 'text': '乒乓球', },{'value': '4', 'text': '羽毛球'}, ],selected_value_list=['1', '3']))select_int_val = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=MultiSelect(text_value_list=[{'value': 1, 'text': '篮球', },{'value': 2, 'text': '足球', },{'value': 3, 'text': '乒乓球', },{'value': 4, 'text': '羽毛球'}, ]))select_int_val_default = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=MultiSelect(text_value_list=[{'value': 1, 'text': '篮球', },{'value': 2, 'text': '足球', },{'value': 3, 'text': '乒乓球', },{'value': 4, 'text': '羽毛球'}, ],selected_value_list=[2]))

d. 动态select选项

        class DynamicSelectForm(Form):city = IntegerField(error={'required': '年龄不能为空', 'invalid': '年龄必须为数字'},widget=SingleSelect(text_value_list=[{'value': 1, 'text': '上海'},{'value': 2, 'text': '北京'},{'value': 3, 'text': '广州'}]))multi_favor = IntegerListField(error={'required': '请选择爱好', 'invalid': '选择爱好格式错误'},widget=MultiSelect(text_value_list=[{'value': 1, 'text': '篮球', },{'value': 2, 'text': '足球', },{'value': 3, 'text': '乒乓球', },{'value': 4, 'text': '羽毛球'}, ]))def __init__(self, *args, **kwargs):super(DynamicSelectForm, self).__init__(*args, **kwargs)# 获取数据库中的最新数据并显示在页面上(每次创建对象都执行一次数据库操作来获取最新数据)self.city.widget.text_value_list = [{'value': 1, 'text': '上海'},{'value': 2, 'text': '北京'},{'value': 3, 'text': '南京'},{'value': 4, 'text': '广州'}]self.multi_favor.widget.text_value_list = [{'value': 1, 'text': '篮球'},{'value': 2, 'text': '足球'},{'value': 3, 'text': '乒乓球'},{'value': 4, 'text': '羽毛球'},{'value': 5, 'text': '玻璃球'}]

写在最后

开源组件持续更新中,如您在使用过程中遇到任何问题,请留言,我将尽快回复!!!

Tyrion技术交流QQ群:564068039

Tyrion技术交流QQ群:564068039

Tyrion技术交流QQ群:564068039

重要的事情说三遍....

...

......

.........

............

.................  

Tyrion中文文档(含示例源码)相关推荐

  1. DL4J中文文档/开始/从源码构建

    在本地从主干构建 注意:大多数用户应该使用Maven Central上的快速入门指南,而不是从源代码构建. 除非你有一个非常好的从源码构建的理由(例如开发新的特性--不包括自定义层.自定义激活函数.自 ...

  2. Tyrion 中文文档(含示例源码)

    原文出处: Mr.Seven   Tyrion是一个基于Python实现的支持多个WEB框架的Form表单验证组件,其完美的支持Tornado.Django.Flask.Bottle Web框架.Ty ...

  3. Tyrion (含示例源码)

    http://www.cnblogs.com/wupeiqi/articles/5938916.html 转载于:https://www.cnblogs.com/wumingxiaoyao/p/673 ...

  4. vue - element <upload> 组件批量上传文档,可携带其他表单数据项一同与文件 “手动提交“ 服务器(类似百度文库系统批量上传前端界面与逻辑)超详细教程示例源码,提供界面与逻辑完整源码

    效果图 本示例使用的是 element 组件库,其实什么组件库都行(逻辑是一样),只要你是 vue.js 项目就能使用本教程. 本文实现了 vue + element 使用 upload 组件批量上传 ...

  5. 最好用的python音频库之一:pydub的中文文档(含API)

    pydub 中文文档(含API) 0x00 写在最前 Pydub lets you do stuff to audio in a way that isn't stupid. pydub 提供了简洁的 ...

  6. 使用JavaScript生成二维码教程-附qrcodejs中文文档

    使用javascript生成二维码 依赖jquery 需要使用到的库 https://github.com/davidshimj... DIV <div id="qrcode" ...

  7. 【图像去噪】基于matlab GUI butterworth+中值+维纳+小波图像去噪【含Matlab源码 520期】

    ⛄一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[图像去噪]基于matlab GUI butterworth+中值+维纳+小波图像去噪[含Matlab源码 520期] 获取代码方式2: ...

  8. 【图像去噪】基于matlab小波滤波(硬阙值+软阙值)+中值滤波图像去噪【含Matlab源码 462期】

    一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[图像去噪]基于matlab小波滤波(硬阙值+软阙值)+中值滤波图像去噪[含Matlab源码 462期] 获取代码方式2: 通过订阅紫极神光 ...

  9. 【路径规划】邮政运输网络中的邮路规划和邮车调度【含Matlab源码 648期】

    一.获取代码方式 获取代码方式1: 完整代码已上传我的资源:[路径规划]邮政运输网络中的邮路规划和邮车调度[含Matlab源码 648期] 点击上面蓝色字体,直接付费下载,即可. 获取代码方式2: 付 ...

最新文章

  1. Linux_Rsync远程同步备份服务器
  2. form 表单上传文件及传输数据的编码格式
  3. Objective-C中的@property使用[五]
  4. Oracle-分析函数之取上下行数据lag()和lead()
  5. some more debugging screenshot about timeformat in DatePicker 15
  6. linux指法教程,Linux的vim的使用
  7. vue踩坑-This relative module was not found
  8. zookeeper使用及模拟注册中心原理
  9. [开源 .NET 跨平台 Crawler 数据采集 爬虫框架: DotnetSpider] [四] JSON数据解析
  10. Linux命令——lsb_release
  11. (三)映射对象标识符(OID)
  12. Linux中的cp命令老九门
  13. Android文件的读写
  14. css集合——好看的按钮样式+阴影+渐变
  15. 中国地图流动图(一)
  16. 【java图形化用户界面】猜数游戏
  17. 对销售代表的100个忠告
  18. HP DL580 G8 做RAID
  19. 扇贝python骗局_北斗揭獐子岛扇贝骗局:27条采捕船数万航行数据还原轨迹
  20. 高斯列主元消去法解线性方程组

热门文章

  1. 校企合作,人才共育|岳阳开放大学校长乐艳华一行莅临云畅科技考察交流
  2. 喊你来学习:这些技术微信号你关注了吗?
  3. matlab eye函数_[线性代数系列1] MATLAB入门笔记
  4. 隧道人员定位解决方案
  5. 让Word 2007默认文档保存格式为Word 2003的DOC格式
  6. Admin.NET管理系统(vue3等前后端分离)学习笔记--持续更新
  7. SELinux权限问题解决
  8. 用python画一个简单卡通人物画法_Python绘制可爱的卡通人物 | 【turtle使用】
  9. 赛诺菲巴斯德宣布建立专属mRNA疫苗卓越中心;​葛兰素史克单片双药艾滋病治疗药物多伟托在中国上市 | 医药健闻...
  10. 吐血整理!140种Python标准库、第三方库和外部工具都有了