M:Model,模型,和数据库进行交互
V:View,视图,负责产生Html页面
C:Controller,控制器,接收请求,进行处理,与M和V进行交互,返回应答。
- 1、用户点击注
- 2、按钮,将要注册的信息发送给网站服务器。
- 3、 Controller控制器接收到用户的注册信息,Controller会告诉Model层将用户的注册信息保存到数据库
- 4、 Model层将用户的注册信息保存到数据库
- 5、 数据保存之后将保存的结果返回给Model模型,
- 6、 Model层将保存的结果返回给Controller控制器。
- 7、 Controller控制器收到保存的结果之后,或告诉View视图,view视图产生一个html页面。
- 8、 View将产生的Html页面的内容给了Controller控制器。
- 9、 Controller将Html页面的内容返回给浏览器。
- 10、 浏览器接受到服务器Controller返回的Html页面进行解析展示。
项目文件夹下的组成部分:
- manage.py是项目运行的入口,指定配置文件路径。
- 与项目同名的目录,包含项目的配置文件 ___init.py是一个空文件,作用是这个目录可以被当作包使用。
- settings.py是项目的整体配置文件。
- urls.py是项目的URL配置文件。
- wsgi.py是项目与WSGI兼容的Web服务器入口
M:Model,模型,和MVC中的M功能相同,和数据库进行交互。
V:view,视图,和MVC中的C功能相同,接收请求,进行处理,与M和T进行交互,返回应答。
T:Template,模板,和MVC中的V功能相同,产生Html页面
- 1、 用户点击注册按钮,将要注册的内容发送给网站的服务器。
- 2、 View视图,接收到用户发来的注册数据,View告诉Model将用户的注册信息保存进数据库。
- 3、 Model层将用户的注册信息保存到数据库中。
- 4、 数据库将保存的结果返回给Model
- 5、 Model将保存的结果给View视图。
- 6、 View视图告诉Template模板去产生一个Html页面。
- 7、 Template生成html内容返回给View视图。
- 8、 View将html页面内容返回给浏览器。
- 9、 浏览器拿到view返回的html页面内容进行解析,展示。
中间件是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。
5.django中哪里用到了线程,哪里用到了协程,哪里用到了进程?1.Django 中耗时的任务用一个进程或者线程来执行,比如发邮件,使用 celery。
2.部署 django 项目的时候,配置文件中设置了进程和协程的相关配置。
3.django利用多线程增加异步任务.celery消息队列。
4.django中使用多线程发送邮件.send_mail()。
5.django原生为单线程序,当第一个请求没有完成时,第二个请求阻塞,直到第一个请求完成,第二个请 求才会执行. 使用uwsgi编程多并发,使用nginx+uwsgi提供高并发,nginx的并发能力超高,单台并发能力过万 (不绝对).
6.django自带的development server为多线程模式,但是他还有一个小问题就是它不是线程安全的。可能在请求很多时会出现数据不同步,当然,这一般不是问题,因为我们通常只在自己机器上调试时才用Development Server。
6.django关闭浏览器,怎么清除cookies和session?cookie是有过期时间的,如果不指定,默认关闭浏览器之后cookie就会过期。 如果 SESSION_EXPIRE_AT_BROWSER_CLOSE 设置为 False ,cookie可以在用户浏览器中保持有效达 SESSION_COOKIE_AGE 秒(存活时间)。 如果不想用户每次打开浏览器都必须重新登陆的话,可以用这个参数。 如果 SESSION_EXPIRE_AT_BROWSER_CLOSE 设置为 True ,当浏览器关闭时,Django会使cookie失效
Django中操作session: session也是有过期时间,如果不指定,默认两周就会过期。 request.session.set_expiry(0);那么当浏览器关闭时,session失效
删除session:del request[key]
7.Django里QuerySet的get和filter方法的区别1、输入参数
- get 的参数只能是model中定义的那些字段,只支持严格匹配
- filter 的参数可以是字段,也可以是扩展的where查询关键字,如in,like等
2、返回值
- get 返回值是一个定义的model对象
- filter 返回值是一个新的QuerySet对象,然后可以对QuerySet在进行查询返回新的QuerySet对象,支持链式操作,QuerySet一个集合对象,可使用迭代或者遍历,切片等,但是不等于list类型(使用一定要注意)
3、异常
- get 只有一条记录返回的时候才正常,也就说明get的查询字段必须是主键或者唯一约束的字段。当返回多条记录或者是没有找到记录的时候都会抛出异常
- filter 有没有匹配的记录都可以。
8.简述Django对http请求的执行流程在接受一个Http请求之前的准备
启动一个支持WSGI网关协议的服务器监听端口等待外界的Http请求,比如Django自带的开发者服务器或者uWSGI服务器。
服务器根据WSGI协议指定相应的Handler来处理Http请求,并且初始化该Handler,在Django框架中由框架自身负责实现这一个Handler。 此时服务器已处于监听状态,可以接受外界的Http请求 当一个http请求到达服务器的时候 服务器根据WSGI协议从Http请求中提取出必要的参数组成一个字典(environ)并传入Handler中进行处理。
在Handler中对已经符合WSGI协议标准规定的http请求进行分析,比如加载Django提供的中间件,路由分配,调用路由匹配的视图等。 返回一个可以被浏览器解析的符合Http协议的HttpResponse。
9.简述Django下的(内建)缓存机制Django根据设置的缓存方式,浏览器第一次请求时,cache会缓存单个变量或整个网页等内容到硬盘或者内存中,同时设置response头部,当浏览器再次发起请求时,附带f-Modified-Since请求时间到Django,Django 发现f-Modified-Since会先去参数之后,会与缓存中的过期时间相比较,如果缓存时间比较新,则会重新请求数据,并缓存起来然后返回response给客户端,如果缓存没有过期,则直接从缓存中提取数据,返回给response给客户端。
10.Form表单的提交和ajax的提交1、提交方式
form表单通常是通过在HTML中定义的action,method及submit来进行表单提交,另外也可以通过在js中调用submit函数来进行表单提交。 具体的提交方式有很多种,比如可以通过封装成XMLHttpRequest对象进行提交。
Ajax是基于XMLHttpRequest进行的。
2、页面刷新
Form提交,更新数据完成后,需要转到一个空白页面再对原页面进行提交后处理。哪怕是提交给自己本身的页面,也是需要刷新的,因此局限性很大。
Ajax可以实现页面的局部刷新,整个页面不会刷新。
3、请求由谁来提交
Form提交是浏览器完成的,无论浏览器是否开启JS,都可以提交表单。
Ajax是通过js来提交请求,请求与响应均由js引擎来处理,因此不启用JS的浏览器,无法完成该操作。
4、是否可以上传文件
最初,ajax出于安全性考虑,不能对文件进行操作,所以就不能通过ajax来实现文件上传,但是通过隐藏form提交则可以实现这个功能,所以这也是用隐藏form提交的主要用途。 后来XMLHttpRequest引入了FormData类型,使得通过Ajax也可以实现文件上传。
11.项目怎么优化?提过哪些建议?对于开发人员来说,网站性能优化一般包括Web前端性能优化、应用服务器性能优化、存储服务器性能优化三类。
Web前端性能优化:
1、减少http请求
http协议是无状态的应用层协议,意味着每次http请求都需要建立通信链路、进行数据传输,而在服务器端,每个http请求都需要启动独立的线程去处理。减少http请求的数目可有效提高访问性能。减少http的主要手段是合并CSS、合并javascript、合并图片。
2、使用浏览器缓存
对一个网站而言,CSS、javascript、logo、图标,这些静态资源文件更新的频率都比较低,而这些文件又几乎是每次http请求都需要的。如果将这些文件缓存在浏览器中,可以极好的改善性能。通过设置http头中的cache-control和expires的属性,可设定浏览器缓存,缓存时间可以自定义。
3、启用压缩
在服务器端对文件进行压缩,在浏览器端对文件解压缩,可有效减少通信传输的数据量。如果可以的话,尽可能的将外部的脚本、样式进行合并,多个合为一个。文本文件的压缩效率可达到80%以上,因此HTML、CSS、javascript文件启用GZip压缩可达到较好的效果。但是压缩对服务器和浏览器产生一定的压力,在网络带宽良好,而服务器资源不足的情况下要综合考虑。
4、CSS放在页面最上部,javascript放在页面最下面
浏览器会在下载完成全部CSS之后才对整个页面进行渲染,因此最好的做法是将CSS放在页面最上面,让浏览器尽快下载CSS。 Javascript则相反,浏览器在加载javascript后立即执行,有可能会阻塞整个页面,造成页面显示缓慢,因此javascript最好放在页面最下面。
应用服务器优化
应用服务器也就是处理网站业务的服务器,网站的业务代码都部署在这里,主要优化方案有缓存、异步、集群等。
1、合理使用缓存
当网站遇到性能瓶颈时,第一个解决方案一般是缓存。在整个网站应用中,缓存几乎无处不在,无论是客户端,还是应用服务器,或是数据库服务器。在客户端和服务器的交互中,无论是数据、文件都可以缓存,合理使用缓存对网站性能优化非常重要。
缓存一般用来存放那些读写次数比较高,变化较少的数据,比如网站首页的信息、商品的信息等。应用程序读取数据时,一般是先从缓存中读取,如果读取不到或数据已失效,再访问磁盘数据库,并将数据再次写入缓存。
缓存的基本原理是将数据存储在相对有较高访问速度的存储介质中,比如内存。一方面缓存访问速度快,另一方面,如果缓存的数据是需要经过计算处理得到的,那使用缓存还可以减少服务器处理数据的计算时间。
使用缓存并不是没有缺陷:内存资源是比较宝贵的,不可能将所有数据都缓存,一般频繁修改的数据不建议使用缓存,这会导致数据不一致。 网站数据缓存一般遵循二八定律,即80%的访问都在20%的数据上。所以,一般将这20%的数据缓存,可以起到改善系统性能,提高服务器读取效率。
2、异步操作
使用消息队列将调用异步化,可以改善网站系统的性能。
在不使用消息队列的情况下,用户的请求直接写入数据库,在高并发的情况下,会对数据库造成非常大的压力,也会延迟响应时间。
在使用消息队列后,用户请求的数据会发送给消息队列服务器,消息队列服务器会开启进程,将数据异步写入数据库。消息队列服务器的处理速度远超过数据库,因此用户的响应延迟可得到改善。
消息队列可以将短时间内的高并发产生的事务消息,存储在消息队列中,从而提高网站的并发处理能力。在电商网站的促销活动中,合理使用消息队列,可以抵御短时间内用户高并发的冲击。
3、使用集群
在网站高并发访问的情况下,使用负载均衡技术,可以为一个应用构建由多台服务器组成的服务器集群,将并发访问请求,分发到多台服务器上处理,避免单一服务器因负载过大,而导致响应延迟。
4、代码优化
网站的业务逻辑代码主要部署在应用服务器上,需要处理复杂的并发事务。合理优化业务代码,也可以改善网站性能。
任何web网站都会遇到多用户的并发访问,大型网站的并发用户会达到数万。每个用户请求都会创建一个独立的系统进程去处理。由于线程比进程更轻量,占用资源更少,所以,目前主流的web应用服务器都采用多线程的方式,处理并发用户的请求,因此,网站开发多数都是多线程编程。
使用多线程的另一个原因是服务器有多个CPU,现在手机都到了8核CPU的时代,一般的服务器至少是16核CPU,要想最大限度的使用这些CPU,必须启动多线程。
那么,启动多少线程合适呢?
启动线程数和CPU内核数量成正比,和IO等待时间成正比。如果都是计算型的任务,那么线程数最多不要超过CPU内核数,因为启动再多,CPU也来不及调用。如果任务是等待读写磁盘、网络响应,那么多启动线程会提高任务并发度,提高服务器性能。 或者用个简化的公式来描述: 启动线程数 = (任务执行时间/(任务执行事件 - IO等待时间)) * CPU内核数
存储优化
数据的读写是网站处理并发访问的另一瓶颈。使用缓存虽然可以解决一部分数据读写压力,但很多时候,磁盘仍然是系统最严重的瓶颈。而且磁盘是网站最重要的资产,磁盘的可用性和容错性也至关重要。
机械硬盘和固态硬盘:机械硬盘是目前最常用的硬盘,通过马达带动磁头到指定磁盘的位置访问数据,每次访问数据都需要移动磁头,在读取连续数据和随机访问上,磁头移动的次数相差巨大,因此机械硬盘的性能表现差别巨大,读写效率较低。而在网站应用中,大多数数据的访问都是随机的,在这种情况下,固态硬盘具有更高的性能。但目前固态硬盘在工艺上、数据可靠性上还有待提升,因此固态硬盘的使用尚未普及,从发展趋势看,取代机械硬盘应该是迟早的事情。
总结:
网站性能优化是在用户高并发访问,网站遇到问题时的解决方案。所以网站性能优化的主要内容是改善高并发用户访问情况下的网站响应速度。
网站性能优化的最终目的是改善用户的体验。但性能优化本身也是需要综合考虑的。比如说,性能提高一倍,服务器数量也要增加一倍,这样的优化是否可以考虑?
技术是由业务驱动的,离开业务的支撑,任何性能优化都是空中楼阁。
12.Flask和Django路由映射的区别?在django中,路由是浏览器访问服务器时,先访问的项目中的url,再由项目中的url找到应用中url,这些url是放在一个列表里,遵从从前往后匹配的规则。
在flask中,路由是通过装饰器给每个视图函数提供的,而且根据请求方式的不同可以一个url用于不同的作用。
13.Flask中正则URL的实现?@app.route('')中URL显式支持string、int、float、path 4种类型,隐式支持正则
第一步:写正则类,继承BaseConverter,将匹配到的值设置为regex的值
class RegexUrl(BaseConverter):
def __init__(self, url_map, *args):
super(RegexUrl, self).__init__(url_map)
self.regex = args[0]
第二步:把正则类赋值给我们定义的正则规则
app.url_map.converters['re'] = RegexUrl
第三步:在URL中使用正则
@app.route('/regex/')
def regex111(id):
return 'id:%s'%id
14.Flask中请求上下文和应用上下文的区别和作用?- current_app、g就是应用上下文
- requests、session就是请求上下文
手动创建上下文的两种方法:
- with app.app_context()
- app = current_app._get_current_object()
{{ expression | filter1 | filter2 | ... }} 即 表达式(expression)使用filter1过滤后再使用filter2过滤..
16.Flask中数据库app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']设置的作用?
作用:可以配置请求执行完逻辑之后自动提交,而不用我们每次都手动调用session.commit()
补充:
监听数据库中的数据,当发生改变,就会显示一些内容 app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=True
显示打印的数据以及sql语句,建议不设置,默认为False app.config['SQLALCHEMY_ECHO'] = True
17.模糊查询和精确查询的区别?filter()模糊查询
把过滤器添加到原查询上,返回一个新查询。
filter_by()精确查询
把等值过滤器添加到原查询上,返回一个新查询
18.对flask蓝图(Blueprint)的理解?1.蓝图定义
蓝图/Blueprint是Flask应用程序组件化的方法,可以在一个应用内或跨越多个项目共用蓝图。使用蓝图可以极大地简化大型应用的开发难度,也为Flask扩展提供了一种在应用中注册服务的集中式机制。
2.蓝图的应用场景
1.把一个应用分解为一个蓝图的集合。这对大型应用是理想的。一个项目可以实例化一个应用对象,初始化几个扩展,并注册一集合的蓝图。
2.以 URL 前缀和/或子域名,在应用上注册一个蓝图。 URL 前缀/子域名中的参数即成为这个蓝图下的所有视图函数的共同的视图参数(默认情况下)。
3.在一个应用中用不同的 URL 规则多次注册一个蓝图。
4.通过蓝图提供模板过滤器、静态文件、模板和其它功能。一个蓝图不一定要实现应用或者视图函数。
5.初始化一个 Flask 扩展时,在这些情况中注册一个蓝图。
3.蓝图的缺点
不能在应用创建后撤销注册一个蓝图而不销毁整个应用对象。
4.使用蓝图的三个步骤
1.创建 一个蓝图对象
blue = Blueprint("blue",__name__)
2.在这个蓝图对象上进行操作 ,例如注册路由、指定静态文件夹、注册模板过滤器...
@blue.route('/')
def blue_index():
return 'Welcome to my blueprint'
3.在应用对象上注册这个蓝图对象
app.register_blueprint(blue,url_prefix='/blue')
19.跨站请求伪造和跨站请求保护的实现?1、图中Browse是浏览器,WebServerA是受信任网站/被攻击网站A,WebServerB是恶意网站/攻击网站B。
(1)一开始用户打开浏览器,访问受信任网站A,输入用户名和密码登陆请求登陆网站A。
(2)网站A验证用户信息,用户信息通过验证后,网站A产生Cookie信息并返回给浏览器。
(3)用户登陆网站A成功后,可以正常请求网站A。
(4)用户未退出网站A之前,在同一浏览器中,打开一个TAB访问网站B。
(5)网站B看到有人访问后,他会返回一些攻击性代码。
(6)浏览器在接受到这些攻击性代码后,促使用户不知情的情况下浏览器携带Cookie(包括sessionId)信息,请求网站A。这种请求有可能更新密码,添加用户什么的操作。
2、从上面CSRF攻击原理可以看出,要完成一次CSRF攻击,需要被攻击者完成两个步骤:
(1)登陆受信任网站A,并在本地生成COOKIE。
(2)在不登出A的情况下,访问危险网站 B。
如果不满足以上两个条件中的一个,就不会受到CSRF的攻击
3、以下情况可能会导致CSRF:
1.登录了一个网站后,打开一个tab页面并访问另外的网站。
2.关闭浏览器了后,本地的Cookie尚未过期,你上次的会话还没有已经结束。(事实上,关闭浏览器不能结束一个会话,但大多数人都会错误的认为关闭浏览器就等于退出登录/结束会话了……)
解决办法:就是在表单中添加from.csrf_token
20.Flask项目中如何实现session信息的写入?flask中有三个session:
第一个:数据库中的session,例如:db.session.add()
第二个:在flask_session扩展中的session,使用:from flask_session import Session,使用第三方扩展的session可以把信息存储在服务器中,客户端浏览器中只存储sessionid
第三个:flask自带的session,是一个请求上下文, 使用:from flask import session。自带的session把信息加密后都存储在客户端的浏览器cookie中
21.Flask(__name__)中的__name__可以传入哪些值?1、可以传入的参数
(1)字符串:‘hello’,但是‘abc’,不行,因为abc是python内置的模块
(2)__name__,约定俗成
2、不可以插入的参数
(1)python内置的模块,re,urllib,abc等
(2)数字
22. Flask中请求钩子的理解和应用请求钩子是通过装饰器的形式实现的,支持以下四种:
1、before_first_request在处理第一个请求前运行
2、before_request:在每次请求前运行
3、after_request:如果没有未处理的异常抛出,在每次请求后运行
4、teardown_request:即使有未处理的异常抛出,在每次请求后运行
应用:
请求钩子
@api.after_request
def after_request(response):
设置默认的响应报文格式为application/json
如果响应报文response的Content-Type是以text开头,则将其改为默认的json类型
If response.headers.get("Content-Type").startswith("text"):
response.headers["Content-Type"] = "application/json" return response
23.自定义过滤器的步骤?@app.route('')中 URL 显式支持 string、int、float、path uuid any 6 种类型,隐式支持正 则。
第一步:写正则类,继承 BaseConverter,将匹配到的值设置为 regex 的值。
class RegexUrl(BaseConverter):
def __init__(self, url_map, *args):
super(RegexUrl, self).__init__(url_map)
self.regex = args[0]
第二步:把正则类赋值给我们定义的正则规则。
app.url_map.converters['re'] = RegexUrl
第三步:在 URL 中使用正则。
@app.route('/regex/')
def regex111(id):
return 'id:%s'%id
25.Flask 中请求上下文和应用上下文的区别和作用?
current_app、g 是应用上下文。
request、session 是请求上下文。
手动创建上下文的两种方法:
- with app.app_context()
- app = current_app._get_current_object()
两者区别:
- 请求上下文:保存了客户端和服务器交互的数据。
- 应用上下文:flask 应用程序运行过程中,保存的一些配置信息,比如程序名、数据库连接、应用 信息等。
两者作用:
请求上下文(request context): Flask 从客户端收到请求时,要让视图函数能访问一些对象,这样才能处理请求。请求对象是一 个很好的例子,它封装了客户端发送的 HTTP 请求。 要想让视图函数能够访问请求对象,一个显而易见的方式是将其作为参数传入视图函数,不过这会导致程序中的每个视图函数都增加一个参数,除了访问请求对象,如果视图函数在处理请求时还要访问其他对象,情况会变得更糟。为了避免大量可有可无的参数把视图函数弄得一团糟,Flask 使用上下文临时把某些对象变为全局可访问。
应用上下文(application context): 它的字面意思是应用上下文,但它不是一直存在的,它只是 request context 中的一个对 app 的代理(人),所谓 local proxy。它的作用主要是帮助 request 获取当前的应用,它是伴 request 而 生,随 request 而灭的。
26.Flask 中数据库设置?app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test'
# 动态追踪修改设置,如未设置只会提示警告
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
#查询时会显示原始 SQL 语句
app.config['SQLALCHEMY_ECHO'] = True
补充:
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN']:可以配置请求执行完逻辑之后自动提 交,而不用我们每次都手动调用 session.commit();
监听数据库中的数据,当发生改变,就会显示一些内容: app.config['SQLALCHEMY_TRACK_MODIFICATIONS']=True;
显示打印的数据以及 sql 语句,建议不设置,默认为 False: app.config['SQLALCHEMY_ECHO'] = True。
27.常用的 SQLAlchemy 查询过滤器?在 Flask 中,为了处理 web 表单,我们一般使用 Flask-WTF 扩展,它封装了 WTForms,并且它有 验证表单数据的功能。
WTForms 支持的 HTML 标准字段:
WTForms 常用验证函数
使用 Flask-WTF 需要配置参数 SECRET_KEY。
CSRF_ENABLED 是为了 CSRF(跨站请求伪造)保护。 SECRET_KEY 用来生成加密令牌,当 CSRF 激活的时候,该设置会根据设置的密匙生成加密令牌。
29.项目接口实现后路由访问不到怎么办?1.可以通过 postman 测试工具测试,或者看 log 日志信息找到错误信息的大概位置。
2.断点调试
30.Flask 中 url_for 函数?1.URL 反转:根据视图函数名称得到当前所指向的 url。
2.url_for() 函数最简单的用法是以视图函数名作为参数,返回对应的 url,还可以用作加载静态文件。
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?