完美电竞·(世界)官方网站

Flask 10天开发一个升博体育网站

时间:2023-07-24


  升博体育偶然找到一篇两年半前大二时写的文章,记录了十天内是怎么完成一个网站的,很多内容现在看起来都过时了,文风和代码也有各种槽点(切勿模仿!),但还是想发布出来,毕竟记录了一个曾经奋斗的自己:)

  1.在Ubuntu中新建一个目录,用virtualenv创建好虚拟环境,用pip安装flask,接着测试一下。

  3.在虚拟机中使用ifconfig命令查看ip地址,然后配置好ssh的选项,连接前记得已经在虚拟机中安装好ssh-server,因为默认它是只有ssh-client而没有ssh的服务器的,用apt-get install openssh-server安装之,用户和密码为虚拟机中的用户名和密码。

  6.把代码同步到远程主机上,Upload to直接把代码推送到虚拟机的项目路径中,Sync with Deployed to..查看项目部署的文件状态和选择同步的文件。

  可以看到,flask的程序已经开始启动,但是这里要注意,在本机是不能够直接访问虚拟机上的localhost的,所以这里的127.0.0.1:5000/是指在虚拟机的服务,而在host这边是无法通过此路径查看的。那怎么办?之前我们说过在虚拟机中配置了nginx,此时它的作用就来了,总所周知,nginx的其中一个常见用途就是作反向代理,于是,在这里我们也用nginx代理flask程序。

  (其实这里也有另外一种方法,就是在Paralles中的网络设置里面配置端口映射,这样就有办法在host主机中访问到虚拟机的localhost了。)

  我们的nginx服务器监听了虚拟机的80端口,把跟路径的request转发到flask绑定的5000端口,而静态文件路径(/static)的请求则绕过flask,直接访问虚拟机上的文件目录,这样也有效地减轻了flask程序的负荷。

  首先从WTF扩展中导入Form类,我们要定义的表单类会继承到这个Form类,接下来简单地为表单定义三个域,两个文本输入框,validators中加入了wtforms.validators中的DataRequired的实例,它将会把这两个文本框设置为必填项。最后还有一个提交域,也就是提交该表单的按钮。

  蓝本(Flask-Blueprint)有许多用途,其中一个常见的用途即是为应用的模块做url的划分。

  在Blueprint的参数中还可以指定模块的静态文件路径以及模版文件路径。

  为应用编写错误的响应视图十分重要,这里简单地定义了两个视图,分别对应错误404和错误500的响应,注意这里使用的main为上一个中定义的蓝本对象,若在英语中注册了蓝本,被装饰器包装的视图函数都会注册到应用中,它会把 构建Blueprint时所使用的名称(在本例为simple_page)作为函数端点 的前缀。

  这里定义了首页(/)和比较页(/pk)的对应视图,在index中,我们把之前定义的PkForm表单实例化,作为渲染模版函数render_template的上下文参数传入到模版中渲染。在pk视图中,它接受来自index表单中post提交的数据,因此要在它的装饰器的methods参数中加上POST属性(默认只有GET),注意要把request.form作为表单的构造函数的参数传入,否则表单将不能接收到任何数据,然后我们用表单到validate_on_submit方法来判断表单的数据是否合法,若正确,则把输入框的两个数据拿出,渲染到比较页中,否则,便简单地返回一个显示错误的响应。

  这里简单地在模版定义一个表单,它指向之前定义的pk视图,当然了,只有这么简单的显示是远远不够的,在static中定义css样式文件,在页面的头部的link标签的href属性指定用url_for()反向解析得到的静态文件路径(这里要感谢强大的jinjia2模版:))。

  到这里,应用的框架基本清晰,但我们需要更加灵活的启动和运行应用,在app目录下编写全局的配置文件。

  在BaseConfig中定义了应用的一些基本配置,例如秘钥,邮箱配置等等,下面所有的其它配置都会继承BaseConfig,扩展出的其它配置,这里定义了一个DevConfig(开发配置),顾名思义是在开发中的配置,除此之外,还可以定义其它类型的配置(如生产配置,测试配置等),在DevConfig中我们扩展了关于MongoDB连接(Flask-PyMongo)的配置,以及一个静态方法init_app,它会应用进行一些配置的初始化(如建立数据库的连接)。

  这里编写了一个创建和初始化应用的函数,它将负责为应用初始化传入的配置,使用配置的init_app初始化自身,以及注册前面编写的蓝本。

  接下来开始编写API了,REST(表现层状态转换)设计风格是当前最流行的设计模式,接下来将会为应用编写REST风格的API。

  在app模块的初始化中,我们创建了MongoDB的连接实例,但这个实例是还没有绑定到当前的应用上下文的,因此还要在create_app中为mongo实例用创建出来的app添加到连接实例的init_app方法,这时候升博体育,MongoDB就正式可以在应用中工作了,只需要在其他文件中导入app模块的mongo实例( from app import mongo)。

  接下来,在mongo shell中新建一个存放条目的集合,插入一条数据。。

  这里的两个工具函数(bson_to_json,bson_obj_id)是待会在编写API视图的时候要用到的,其作用分别是把MongoDB的BSON(文档的数据格式)转换为JSON和把id转换为MongoDB中的ObjectId形式,因为这两个功能都难以用python内置的函数实现,而pymongo为我们提供的bson模块提供了很好用的json_util,使得我们很方便地去实现MongoDB和Python之间的数据格式转换。

  终于到了重中之重的步骤了,在Python的Web框架中实现REST API不是一件难事,Python社区也有许多关于REST的包(EVE,REST framework等),而在Flask里,flask默认为开发者提供了可组装视图(Pluggable View),其中里面有一个MethodView,就是专门为开发者设计REST风格的视图的,这种类视图有一个as_view()方法,使用它可以直接把类视图转换成平时使用的普通视图,在有重用视图的需求时,更是比普通函数视图更加地灵活。

  首先,编写好一个API类,继承MethodView,简单地实现get、post、put、delete四个方法,分别对应四个HTTP方法对应的处理句柄。在代码的最后加上路由的规则,映射到不同的方法中,注意get方法中有两种情况,一种是提供id,只返回特定的资源,不提供id则返回所有(或前N条)资源,用add_url_route()方法动态地添加路由。

  最后先简单地实现一下get方法,用pymongo把资源从数据库拉取,find()方法返回的是结果游标,注意这里用到了bson_to_json()方法,前面说过了,这是把MongoDB的文档格式从bson转换为json格式,拿到存放json数据的列表之后,再用json.dumps()返回之。最后客户端得到的就是一个json格式的对象数组了。

  最后的最后要注意的是在find()方法中传入了一个params字典,这个字典是存放GET请求后面带的参数的键值对的,有了条件查询,我们构建的API会更加灵活升博体育。

  这里用Postman向服务器的api地址发送了一个GET请求,参数是之前插入到MongoDB中的文档的id字符串,最后得到一条结果。(若不加参数的话,则得到所有结果)

  再测试了另外一条GET请求,这次则是加上了数据的属性与值作为query string,发送查询请求,结果得到一条记录。

  Sueprvisor是Linux上的一个可以监控应用和进程的工具,我们用它来作为守护进程,自动化地启动和停止应用。

  接下来在应用的目录下新建一个gunicorn的配置文件,里面配置了四个工作进程(wokers)和绑定的端口(bind)。

  除此之外还要创建应用专属的supervisor的配置文件,其中主要的参数有几个:

  用supervisor启动应用进程也非常简单,只需要在supervisorctl的控制台里输入对应的命令即可运行应用。

  当然了,在开发调试环境下还是不太适宜用gunicorn和supervisor来启动应用的,因为这样做不便于查看应用的输出和错误信息,而要在日志中观察应用的运行状态。

  使用Flask-Login扩展能够很方便地为你的应用实现用户的会话和登录功能。

  除此之外,在认证模块要用到Flask-httpauth这个包,我们将在用户的REST API用认证的方式来管理请求。

  1.说到用户模块,当然离不开登录/注册功能,那么我们首先编写登录和注册表单。

  尽管我们的应用没有采用ORM模型的形式,而是用pymongo来直接与MongoDB交互,但我们还是需要编写一个通用的用户模型,一是因为Flask-Login中要用到关于用户的模型对象,二是方便在认证模块中管理用户。

  返回用哈希算法加密后的密码,因为我们的密码是不能让它明文地保存在数据库的升博体育,在这里使用werkzeug.security中的generate_password_hash方法来加密密码。

  在应用模块中新建Flask-Login的LoginManager的实例,用它当前绑定应用,指定用户登录的视图(这里是users.login)。你必须提供一个 user_loader回调。这个回调用于从会话中存储的用户 ID 重新加载用户对象。它应该接受一个用户的ID 作为参数,并且返回相应的用户对象。

  verify_password中提供了两种认证方式,首先是用token认证,如果不通过则用用户+密码的方式入库验证。

  接着用login_requried包装一个获取token的视图和一个资源视图。

  如果不用认证的方式去访问资源的话,会得到一个access denied的响应。

  然后用认证的方式请求token所在的视图,获取到带有过期时间和token的json,下面不用用户名跟密码,而是用token代替去访问应用资源,同样正确地返回资源。

  在完善页面前最好先为模板添加上一些样式,不然页面看起来不美观,也没有层次感,不便于调整页面元素。因此在原来的基础上,可以添加上自己写的样式,用link的方式导出到前端,或者直接使用开源的css框架,在这里使用的是semantic-ui,用bower安装到应用的资源目录,然后就可以编写模板了。

  由于一个网站中通常会有一些重复的基础组件(如导航栏,顶部,通用样式等),这样一来在每个页面文件中我们都要把这些几乎相同的代码拷贝,而且当要改动元素时得每个文件都要进行修改,给开发带来许多的不便,这时候便要用到jinjia2的模板继承功能,使用模板,我们能把这些通用的部分封装出来作为模板,需要替换的地方只需要在特定的位置添加一个块,在继承的子模板中填充块的内容即可。

  1.下面在模板目录下新建一个基础文件(base.html)作为需要继承的通用模板。

  在该目标中包含了一些基本样式和脚本,定义了三个需要填充的块,分别是head头部,主体内容和js文件。

  修改之前定义的首页文件(index.html),用extends的方式继承了父模板,然后只需要在相应的块中补充内容,子模板在渲染的时候便会把块中的内容导出到自身的对应块中,构造和实现页面,这里还把顶部栏(header.html)以及登录框(login.html)分别独立出一个组件,只供特定的模板使用,这样的导入方式会带来更大的灵活性。

  可以把这里的组件理解为页面中的一部分,因此在写代码的时候只需吧对应部分的html元素完成即可。

  现在处理过后的组件可以像积木一样装载在应用上了,这里简单地应用在几个页面,查看效果。

  1.建立创建条目的页面,一个表单搞定,server端向数据库插入一条文档,so easy。

  如下所示,条目内容将会由一个表格来展示,刚创建的条目只有类型一个属性,页面底下会有一个添加属性的按钮,动态地向该条目插入属性。

  由于表格的内容是由python端进行渲染的,而一个条目的属性可能有多种类型升博体育。如下图所示:

  这就带来一个问题,因为属性类型不一定是纯文本,因此不能简单地从数据库取数据然后再直接渲染。

  这里要实现动态的渲染,要在ajax和server端之间定义一套规则,向条目添加属性的时候会按照不同的类型来构造出特定的数据格式,然后python端在知道格式的情况下,用自定义的渲染器实现html的插入。

  当点击添加属性按钮后,底下会折叠处一个标签页菜单,选择不同的类型时,下面的输入框也会相应地变化。

  jinjia2的灵活性使得我们可以方便地在模板中使用python代码,下面定义了一个简单的类型渲染器,根据传入的【属性名,属性值,属性类型】构造出html。

  一开始想用可编辑表格的方式对表格的数据进行即时修改,却发现这样做会带来一些问题,最终放弃之。

  因为之前做的表单验证实在是太简陋了,出于安全考虑,一定要对表单验证(尤其是用户信息方面)加以完善。

  编辑表单文件,在之前的基础上,我们改用一个validators字典来存放不同表单域的规则,在用户名和密码中都加上了长度以及正则表表达式加以限制。

  文件上传有许多种方法,一般用文件系统的io即可,这里使用了mongodb的GridFS系统,mongodb推荐使用它来保存大型文件,

  在flask端,用request.files来接收上传的头像图片,判断图片的扩展名是否符合格式升博体育,如果合法,用werkzurg.utils的secure_filename方法来替换和过滤文件名的特殊字符,接下来实例化GridFS类,它接受一个database和集合作为参数,用fs对象的put方法上传到GridFS,返回的Object Id指向的是db.avatar.files插入的文档,把头像id以及用户的资料信息一并保存到数据库。

  在前端的页面用url_for()方法反向解析出图片的地址,首先要编写好获取头像的路由,它接受头像的Object Id作为参数,从fs系统中取出头像图片的数据,图片的二进制数据会保存在db.avatar.chunks中,这里获取图片之后,构造一个content-type为图片格式的response,否则当打开url时,图片数据不能正确被浏览器解析,在img的src属性中填上路由即可显示图片。

  用户的资料可能有不全的情况,用jinja2的Environment Filter来编写自定义的过滤器,使数据的显示更加人性化。

  有些时候,我们的应用会执行一些后台任务,例如一些不会与用户直接交互,实时性要求较低的动作。例如用户注册的时候,通常会发送一封带有认证token链接的邮件到用户的邮箱,因为发送邮件这个动作会比较耗时,如果同一时间有大量注册的请求,就可能会出现阻塞,影响用户浏览的体验,这时候我们更希望把任务放到后台进行,那么Celery会是一个合适的选择,Celery是一个分布式的任务队列,负责任务的执行与调度。

  首先重构目录的结构,把扩展移到extensions文件下,在init中用工厂函数初始化应用。

  1.在app目录下新建一个tasks目录,里面放的就是Celery要处理的任务文件。

  加上-A参数后Celery会去识别用户自定义的配置文件,后面接一个celery实例所在的模块文件。

  首先把项目用到的配置文件都放在项目的conf目录下,如下图显示了项目的supervisor的配置文件。

  接着编写Dockerfile文件,方便快速地用docker部署好项目的容器环境。

服务支持

我们珍惜您每一次在线询盘,有问必答,用专业的态度,贴心的服务。

让您真正感受到我们的与众不同 !

合作流程

网站制作流程从提出需求到网站制作报价,再到网页制作,每一步都是规范和专业的。

常见问题

提供什么是网站定制?你们的报价如何?等网站建设常见问题。

售后保障

网站制作不难,难的是一如既往的热情服务及技术支持。我们知道:做网站就是做服务,就是做售后。