目录
- 十一、APScheduler
- 自我介绍
一、python
1 数据类型
数据类型:整形、浮点型、字符串、布尔值、列表、字典、集合、元组
2可变、不可变
可变:列表、字典、集合
不可变:数字、字符串、元组
可变不可变指的是内存中的那块空间是否可以被改变
3装饰器、迭代器、生成器
① 装饰器:
在不改变原有函数代码的基础上,在函数执行前后进行自定义操作。装饰器本质是一个闭包函数,就是定义在函数内部用到了外部作用域变量的函数,叫做闭包函数
应用:
- 1 给一些功能【函数】添加记录日志的功能,记录函数的运行时间等等
- 2 比如说flask中的路由就是通过装饰器来映射的,flask中的请求拓展也是通过装饰器操作的
- 3 django中的 权限装饰器、用户登录装饰器等等
【类装饰器】
① 装饰器是类
可以用 __init__
和__call__
来实现给被装饰的函数,添加新的属性和方法等等,主要就是在 __call__
中去添加执行函数前后的逻辑代码
② 给类添加的装饰器
比如在sqlalchemy中的 :
scoped_session的对象,没有session中的方法,比如add
、commit
等等,但是可以使用加在类上的装饰器,给这个类增加属性或者方法
这样scoped_session的对象,就可以使用Session类中的方法
def run():
print('run方法')
def wrapper(my_class):
def inner(*args,**kwargs):
obj = my_class(*args,**kwargs)
# my_class 类的对象增加 run方法
obj.run = run
return obj
return inner
@wrapper
class Duck:
pass
if __name__ == '__main__':
obj = Duck()
# 给类添加了装饰器后,可以给类的对象新增run方法
obj.run()
② 迭代器
可迭代对象:定义了__iter__
方法的对象,可以支持for循环
的对象就是可迭代对象
迭代器:可迭代对象调用__iter__
方法就是迭代器对象,迭代器对象调用__next__()
方法返回容器中的下一个元素,如果没有元素则抛出StopIteration
异常。
应用:
迭代器是一种设计模式,思想是内部保密,无需暴露内部对象;而开放统一的接口给外部
比如一些有规律的数列,规模巨大,我们就可以用迭代器来实现,不必一次性生成所以数据
- 优化代码,节省内存
③ 生成器
有 yield关键字的函数,调用后的结果就是一个生成器,生成器内置了 __iter__
和__next__
方法,所以生成器本质上也是迭代器
应用:
-
生成大量数字
-
处理大型文件的时候,使用生成器可以逐行读取文件并处理文件的内容
-
实时处理数据
-
惰性求值..斐波那契数列
4 上下文管理器
特性:允许程序员在代码块进入和退出时执行一些特定的操作
with语句的代码,有__enter__
和__exit__
方法
__enter__
进入上下文时执行,返回值会赋值给 as 声明的变量__exit__
退出时执行,语句内抛出的异常会被 exit方法的参数接收
应用:比如 django中开启事务
5 深浅拷贝
① 深拷贝
深拷贝:创建一个新对象,会包含原对象中所有的引用的数据
如果原对象发生改变,深拷贝之后的新对象不会受到影响
应用:copy.deepcopy()
② 浅拷贝
浅拷贝:只复制对象的引用,不复制嵌套数据
如果原对象中引用的数据发生改变,新对象也会受到影响
copy()
- 切片
[:]
list()
函数生成的对象也是浅拷贝
6 猴子补丁
在python中就是:在程序运行过程中动态的替换代码
- 应用
- 1 内置的json 效率低换成第三方的 ujson
- 2 django中pymysql模块,替换django中默认使用的sqldb模块
- 3 gevent模块中,猴子补丁用来对所有的io操作和耗时操作打上补丁,动态的将内部会阻塞的模块如【time、socket、os模块】都进行了重写为并发班本
7 io操作与gil
同步代码:io时阻塞,python解释器会释放gil锁,那么这条线程就会被
异步代码:遇到io不释放gil锁,会切切换到别的任务上
8 反射
什么是反射:在程序运行时,利用字符串来操作对象的数据和方法
- hasattr:校验对象是否有指定的属性和方法
- getattr:获取对象的指定属性和方法,如果不存在则返回默认值
- setattr:给对象设置指定的属性和方法
- delattr:删除一个实例或者类中的方法
9 鸭子类型
指的是面向对象中,子类不需要显示的继承某个类,只要有某个的方法和属性,那子类就属于这个类。使用鸭子类型的写法,一旦方法写错了,它就不是这个类型了,容易有问题
python为了解决这个问题:
- 方法1:abc模块,装饰后,必须重写方法,不重写就报错
- 方法2:drf源码中使用的,父类中写个方法, 但没有具体实现,直接抛异常
10 继承、多态、封装
(1)继承
-
继承:表示类与类之间,资源的从属关系,继承父类中的属性和方法的使用权限
-
继承的顺序:
- 在
python3
中只有新式类【继承object及其子类的类】
,新式类:广度优先,逐层查找父类
- 在
-
super()方法:可以
让子类调用父类的方法
,让子类在父类的方法的基础上做拓展
,需要传入调用父类方法传入的参数 -
mro方法:生成一个列表,列表中列出了名字的查找顺序
(2)多态
继承同一个父类的子类,对于父类中方法根据不同需求进行重构,可以识相同函数名实现不同功能
(3)封装
-
确保安全性,有些方法和属性只能在内部访问,对于外部只开放接口访问,用户无需知道内部的举行细节与实现步骤
-
提高代码的重用性
11 类中的方法:动静态方法
① 直接定义在类中的方法
- 默认
绑定给类的实例使用
,产生的实例会自动把自己当做 self参数穿进去 - 而
类也可以使用
但是需要手动传入参数
② classmethod
默认绑定给类
,类调用该函数,自动第一个参数cls就是类本身的名字类产生的对象调用
,会自动将产生该对象的类的名字传入
③ staticmethod
静态方法,无论类和对象谁调用,都要手动传入参数
④ property
将方法伪装成属性,对象通过点的方式就可以得到该方法 返回的值
12 os和pathlib
pathlib是一个从3版本开始就能完全替代os.path的内置库
当需要找多个层级的目录路径时,通过 os.path 需要嵌套写法,如我上面的 project_path ,而 pathlib 可以提供链式写法,简洁明了
os.path 只用于处理路径,如果你想在获取到的路径下做一些事情(如:创建一个目录),你就需要用 os 模块,而 pathlib 可以一站式搞定,将在后面展开讲
13 元类的原理 type和object
元类可以定制类的属性和行为
- type
- type 是所有 Python 类的默认元类
- 用于创建新类,可以使用 type(type_name, superclasses, attributes_dict) 的形式来创建一个新类
-
object
-
object 是所有 Python 类的基类
-
所有 Python 类都直接或间接继承自 object
-
定义了所有 Python 类共有的方法和属性
-
14 python中的接口和 web中的接口
(1)python中没有具体的接口类型,python中的接口是由抽象类与抽象方法实现的,接口本身不识相具体功能,也不包括功能代码,而是由继承他的子类来实现接口的所有的抽象方法
eg:ABC模块
和装饰器abstractmethod
(2)Web 开发中【django中的视图类 视图函数就是接口】
接口(API)是应用程序之间交互的一种方式,可以让应用程序之间共享数据和功能,从而实现更加复杂和丰富的功能。在 Web 开发中,接口通常以 HTTP 协议的形式提供,通过 URL 和请求参数来定义操作和数据。
15 xrange和range
-
xrange:在python2.x的版本中xrange的结果会一次性生成指定范围内的列表,会占用比较多的内存,其结果可以用list函数将其转换为列表
-
range:在python3.x的版本中range的结果是一个的迭代器对象,只有在需要的使用的时候才会生成下一个值,一次值生成一个整数,不能用list函数直接转换
16 参数
python中
-
形式参数:函数定义的时候【有位置参数、默认参数、可变参数、关键字参数】
-
实际参数:调用函数的时候,传入的值是实际参数,可以是常量、变量、表达式
二、celery
python开发的分布式任务调度框架,它使用第三方消息服务来传递任务,目前,Celery支持的消息服务有RabbitMQ、Redis、Amazon SQS
1 目录结构
demo1
- __init__.py
- tasks.py
- run.py
-
tasks.py
from celery import Celery # 通过使用本机redis且没有密码,使用远程redis有密码格式为 # 'redis://:密码@ip:6379/1' broker = 'redis://127.0.0.1:6379/1' # 任务储存 backend = 'redis://127.0.0.1:6379/2' # 结果存储,执行完之后结果放在这 # 创建出app对象 app = Celery(__name__, broker=broker, backend=backend) # 任务通过装饰器@app.task进行装饰 @app.task def add(x, y): return x + y
2.celery 定时任务
在 Celery 中,可以使用 celery-beat 来实现定时任务。Celery Beat 是 Celery 中的一种扩展,它可以定期发送任务消息到 Celery 任务队列中,从而触发预定义的任务。
以下是在 Celery 中创建定时任务的基本步骤:
1. 配置 Celery Beat:在配置 Celery 应用程序时,需要配置 Celery Beat。可以使用 Celery Beat 默认的 Redis 数据库来存储任务调度信息,
``` python
from celery import Celery
from celery.schedules import crontab
app = Celery('myapp', broker='pyamqp://guest@localhost//')
app.conf.beat_schedule = {
'send-email-every-day': {
'task': 'tasks.send_email',
'schedule': crontab(minute=0, hour=8), # 每天上午8点执行
},
}
```
2. 定义定时任务:在 Celery 应用程序中定义定时任务。在这里,可以使用 @app.task 装饰器定义任务,并在其中实现需要执行的代码。
``` python
from celery import Celery
app = Celery('myapp', broker='pyamqp://guest@localhost//')
@app.task
def send_email():
# 实现需要执行的代码
pass
```
3. 启动 Celery Beat:最后,需要使用以下命令启动 Celery Beat:
```
celery -A myapp beat
```
在上面的命令中,-A 参数指定应用程序的名称。
在以上步骤完成后,Celery Beat 将定期发送任务消息到 Celery 任务队列中,从而触发预定义的任务。
4。请注意,在使用 Celery Beat 时,需要启动 Celery worker 和 Celery Beat 进程。可以使用以下命令启动两个进程:
```
celery -A myapp worker --loglevel=info
celery -A myapp beat --loglevel=info
```
在上面的命令中,-A 参数指定应用程序的名称,--loglevel 参数指定日志级别。
3.celery异步任务
- 1 先写一个任务函数: 用celery中的 语法糖
@app.task
来装饰一下 - 2 将这个任务配置到 broker消息中间件中
- 3 在业务逻辑中需要用到 这个任务函数,就通过 delay()方法去调用,就会在celery的worker进程中去消费
delay()方法
在使用 Celery 异步任务队列时,可以将短信发送作为一个异步任务来执行。以下是一个基本的示例:
``` python
from celery import Celery
1 写一个异步任务 配置到 提交到broker中
app = Celery('tasks', broker='pyamqp://guest@localhost//')
# 定义异步任务
@app.task
def send_sms(to, body):
account_sid = 'your_account_sid'
auth_token = 'your_auth_token'
client = Client(account_sid, auth_token)
message = client.messages \
.create(
body=body,
from_='your_twilio_phone_number',
to=to
)
print(message.sid)
2。在应用程序中调用异步任务 使用 delay() 方法将其添加到 Celery 队列中,这样任务将异步地执行,而不会阻塞主线程。
send_sms.delay('+1234567890', 'Hello, this is a test message from Celery!')
```
创建了一个 Twilio 客户端,并使用客户端发送了一条短信。最后,我们在控制台输出了消息的 sid。
最后,在应用程序中调用 send_sms 任务时,我们
3.命令启动 worker 进程,在worker中处理添加的任务
注意,在使用 Celery 进行异步任务时,需要启动 Celery worker 进程来处理任务。您可以使用以下
```
celery -A tasks worker --loglevel=info
```
4.celery延时任务
在 Celery 中,可以使用 delay() 方法来实现延时任务。delay() 方法是 Celery 的 Task 类的一个实例方法,它会将任务消息发送到 Celery 任务队列中,并在一定的时间后执行任务。
以下是使用 delay() 方法创建延时任务的基本步骤:
1. 创建 Celery 应用程序:首先,需要创建一个 Celery 应用程序,用于管理所有的任务。
``` python
from celery import Celery
app = Celery('myapp', broker='pyamqp://guest@localhost//')
```
2. 定义任务:在 Celery 应用程序中定义任务。可以使用 @app.task 装饰器定义任务,并在其中实现需要执行的代码。
``` python
from celery import Celery
app = Celery('myapp', broker='pyamqp://guest@localhost//')
@app.task
def send_email():
# 实现需要执行的代码
pass
```
3. 发送任务消息:在需要执行任务的地方,可以使用 delay() 方法将任务消息发送到 Celery 任务队列中,并指定需要延迟的时间。
``` python
from datetime import timedelta
send_email.delay(countdown=timedelta(seconds=30))
```
在上面的代码中,使用 countdown 参数指定延迟的时间为 30 秒。
请注意,在使用 delay() 方法时,需要启动 Celery worker 进程。可以使用以下命令启动 Celery worker 进程:
```
celery -A myapp worker --loglevel=info
```
在上面的命令中,-A 参数指定应用程序的名称,--loglevel 参数指定日志级别。
二、django
1 django的设计模式
mtv模型:
-
model【模型层】:数据存储层,处理所有数据相关的业务,对数据库的封装与交互 orm
-
template【模版层】:具体来处理页面的显示,将内容呈现到浏览器
-
view【视图层】:业务逻辑层,处理具体的业务逻辑,它的作用是连通Model 层和 Template,用于接收请求、获取数据、返回结果json字符串或者网页
与mvc的区别:
经典MVC模式中,M是指模型,V是视图,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式
- Modle 代表数据存储层,是对数据表的定义和数据的增删改查;
- View 代表视图层,是系统前端显示部分,它负责显示什么和如何进行显示;
- Controller 代表控制层,负责根据从 View 层输入的指令来检索 Model 层的数据,并在该层编写代码产生结果并输出
2 django 的生命周期
1 提交请求:用户在浏览器中输入要访问的网页,浏览器生成响应的request请求,request请求分为请求头和请求体两部分,请求会以 get post方式提交到服务器
2 请求转发:请求进入了WSGI将http数据包装成request请求对象,实际生产环境上是由nginx转发给wsgi
3 中间件:request请求,经过中间件中,从上到下依次执行注册在中间件中的process_request方法,如果返回了HttpResponse对象,那么不再往后执行直接返回给前端
4 路由映射:request对象通过中间件后,如果是FBV会在URL路由映射列表中从前到后逐条匹配,将请求提交到对应的视图函数中;如果是CBV,会执行 as_view 中的 view方法中的 dispatch方法,通过反射去操作定义在视图类中的get、post方法,完成路由分发
5 视图层:在视图层中,实现业务逻辑,如果需要数据库中的数据,则通过django的orm来与数据库进行交互,并在模版层templates中的模版中渲染,处理完完成后将返回 response对象。如果抛出异常,则后面的视图函数则不会执行
6 返回response对象依次从下到上,执行注册了的中间件中的 process_response方法,通过WSGI服务器初始化响应,然后进行response响应
7 浏览器接收到返回的消息对象,解析html、css、js,渲染显示给用户
3 django的信号
django的信号是一种事件触发机制,让应用程序中的不同部分进行通信
比如:在操作模型层对象,删除、保存前后自动触发,或者请求到来前后,抛出异常时触发等等。
操作步骤:
- 1 写一个函数,写好信号触发时候的逻辑,且参数设置成可变长参数,因为内置信号会自动传入一些参数
- 2 绑定内置信号和自定义函数【装饰器或者 connect方法】
- 3 等待自动触发即可
应用场景:
- 做数据同步,解决双写一致性的问题,更新缓存数据库中的数据
- 异地登录、修改密码的时候给用户发送邮件,发送短信
- 用户上传文件的时候记录日志等等
4 django中的orm
① 简介
orm就是对象关系映射object relationship map
将django模型层中的类、对象、对象的属性 映射到数据库中的表、记录、字段对应的值
② 操作方法:
- 1 在models.py中编写类
- 2 执行迁移同步命令
- 3 通过对象点 点 点即可操作数据库
常见方法 c u r d , create、 update、delete、filter等等
5 django中的auth模块
① 简介
auth模块是django自带的用户认证模块
比如用户的 注册、登录、认证、注销、修改密码等等功能,可以通过auth模块快速实现, 默认使用auth_user表来存储用户数据
② django-admin
③ auth模块中的方法
-
create_user
创建加密密码的普通用户 -
auth.authenticate
校验用户是否已经存在存在返回该对象,不存在返回
none
-
auth.login
用户输入用户密码,通过auth.authenticate
的校验后,传入request
对象和用户
对象,则可以自动操作django_session
表创建session
,在客户端记录cookies
保存登录状态 -
request.user
登录成功后,直接request.use
r获取当前登录对象如果没登录获取到的是 匿名对象
AnonymousUser
-
request.user.is_authenticated
判断当前对象是匿名用户还是登录用户 -
auth
校验用户是登陆装饰器login_required
-
检验密码
校验原密码
request.user.check_password(原密码)
修改密码
request.user.set_password(新密码)
保存
request.user.save()
-
退出登录·
auth.logout(request)
6 django的中间件
django 中间件,遵循了插拔式设计【importlib模块:通过传一个字符串形式的路径,将字符串导入模块】
(1)内置中间件有哪些
1 SecurityMiddleware 验证请求安全相关,比如设置XSS防御的请求头,比如做了http协议转为https协议的工作等。
2 SessionMiddleware 处理session相关的session中间件,会给request添加一个处理好的session对象
3 CommonMiddleware slash的问题,路由带不带斜杠d
4 CsrfViewMiddleware scrf认证 主要用于csrf跨站请求伪造,在提交表单的时候会必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击,SessionMiddleware必须出现在CsrfMiddleware之前。
5 AuthenticationMIddleware 用户认证相关
会给request添加一个user对象的中间件。该中间件必须在sessionmiddleware后面。
6 MessageMiddle 消息框架相关 消息中间件
消息处理中间件。为了在多个模板中可以使用我们返回给模板的变量,并且简化操作。
7 XFrameOptionsMiddleware 放点击劫持中间件,防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现
(2)中间件中的方法
-
在请求来的时候,执行顺序是从上到下的,执行
process_request
方法如果 方法返回了HttpReponse对象,name不再往后执行,直接返回给前端
-
在响应走的时候,执行顺序是从下到上的,执行
process_response
方法该方法必须要有两个形参 request和response
-
process_view
方法,在路由匹配之后,执行视图函数前自动触发 -
process_exception
执行视图函数,报错之后自动触发,执行顺序从下往上 -
process_template_response
只要形参中有response的都需要返回,当视图函数/类中返回一个HttpResponse对象,并且对应一个方法的时候自动触发(执行顺序同process_response从下往上)
(3)项目中的中间件
① 添加记录日志的功能
② 添加白名单黑名单
7 django的内置类
① 路由层:
django.urls.URLPattern: 这是URL模式的基类,用于定义URL路由和视图函数之间的映射关系。
② 视图层:
-
django.views.View: 这是所有视图的基类,用于处理HTTP请求并返回HTTP响应。
-
django.contrib.auth.models.User: 这是Django自带的用户模型类,用于处理用户认证和授权。
-
django.forms.Form: 这是所有表单的基类,用于验证和处理用户提交的数据。
③ 模型层orm
- django.db.models.Model: 这是所有Django模型的基类,用于定义数据库中的数据模型。
- django.middleware.MiddlewareMixin: 这是中间件的基类,用于处理HTTP请求和响应,类似于拦截器或过滤器。
④ 中间件:
django.middleware.MiddlewareMixin: 这是中间件的基类,用于处理HTTP请求和响应,类似于拦截器或过滤器。
①②③④⑤⑥⑦⑧⑨⑩ ```python
三、drf
1 restful规范
① 简介
一种定义 web api接口的设计风格与平台语言框架无关,认为后端就是提供数据资源的
并且对于数据资源通过post 、delete、get、update对应增删查改
② 内容
- 需要考虑安全的数据用https来传输
- 路径中带api标志
- 路径中带版本标志
- 数据就是资源,接口用名词表示
- 资源操作 由请求方法来决定
- 在请求地址中带过滤条件
- 规定了响应状态码
- 返回数据中带错误信息
- get返回所有数据为列表单个为对象,post新增返回对象,put修改返回完整对象,delete删除返回空文档
- 响应数据中带链接
2 drf 的三大认证
认证、权限、频率,在APIView
中的dispatch
方法内的self.initial(request, *args, **kwargs)
进入三大认证
# 认证组件:校验用户 - 游客、合法用户、非法用户
# 游客:代表校验通过,直接进入下一步校验(权限校验)
# 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
# 非法用户:代表校验失败,抛出异常,返回403权限异常结果
# 只要通过认证不管是游客还是登录用户,request.user都有值
self.perform_authentication(request)
# 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色
# 认证通过:可以进入下一步校验(频率认证)
# 认证失败:抛出异常,返回403权限异常结果
self.check_permissions(request)
# 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
# 没有达到限次:正常访问接口
# 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
self.check_throttles(request)
(1)认证
-
认证类可以配置多个
-
全局
、局部
、默认配置
的优先级
1.局部(视图类中)- 对于对应的视图类生效
2.全局(settings.py
中)- 对于全局的视图类生效
3.默认(默认配置文件中)
- 自定义认证:继承
BaseAuthentication
,重写authenticate
方法 - 认证类中返回了当前登录用户
(2)权限
-
权限校验和认证校验必须同时使用,并且权限校验是排在认证校验之后的,在源码中可以查找到其执行顺序
-
自定义权限:编写一个权限类,继承【权限模块】中的
BasePermission
,重写has_permission
方法 -
全局使用与局部使用
全局:
settings.py
中配置局部:在视图类中配置
(3)频率
-
访问频率的限制,可以进行对爬虫等恶意行为进行预防
-
编写一个频率类,继承【频率模块】中的
SimpleRateThrottle
,重写get_cache_key
方法 -
全局使用和局部使用
全局:settings.py中配置
局部:对单独的视图类生效
drf的过滤、分页、排序
(1)过滤
- 内置
- 第三方
- 自定义
3 异常处理
在drf中异常分为两种:(1)drf的异常 (2)非drf的异常
【drf的异常】会被【drf内置的函数】捕获,比如【三大认证,视图类的方法】出现了异常,就会被【内置函数捕获后统一处理】
DRF的异常处理为:APIException
Django的异常处理为:Http404
和PermissionDenied
4 drf解决跨域问题
-
跨域问题:由于同源策略而产生
-
同源策略:
是为了保证浏览器的安全,繁殖网站通过js代码,恶意访问用户的敏感信息。要求 请求的url地址,必须和浏览器上的url地址处于 域名、端口、协议都相同的域时,才能访问
-
解决方法:
(1) cors跨域资源共享:后端代码控制
-
简单请求:请求头中增加一个字段Origin
-
非简单请求:浏览器发送预检请求,服务器回答肯定答复,也就是当options请求时,在该次响应的响应头中加东西
在项目上是使用第三方模块,或者自己编写跨域中间件来解决的
(2)nginx反向代理:使用代理服务器时,代理服务器对外就表现为一个服务器,不会出现跨域问题
5 jwt认证
(1)简介
json web token
的简称,与语言和框架无关,时一种基于json的开放标准
(2)构成
jwt本质就是token,由三部分组成
头:header
,声明了类型和算法
荷载:payload
,存放一些有效信息,不可存放敏感信息
签证:signature
,由前两部分
以及 加盐信息
通过声明的加密算法加密后 组成
这样的token
更加具有安全性
(3)优点:无需在服务端存储,减轻了服务器的负担,并且在多个应用之间共享身份验证信息
6 session、cookie、token
- session与cookie
由于http请求的特性:无状态、无连接,所以服务端和客户端之间不会记录状态,所以最开始出现了session-会话标识
就是一个随机字符串,登录的时候,将session-随机字符串
发送给服务端,之后每次发送http请求只需要发送session
,服务端就能辨别出是谁在登录
那这样一个 随机字符串,存在服务端叫做 session 存在客户端就是cookie
- 基于服务器的验证出现的问题
- Seesion:每次认证用户发起请求时,服务器需要去创建一个记录来存储信息。当越来越多的用户发请求时,内存的开销也会不断增加。
- 可扩展性:在服务端的内存中使用Session存储登录信息,占用资源的问题
- CORS(跨域资源共享):当我们需要让数据跨多台移动设备上使用时,跨域资源的共享会是一个让人头疼的问题。在使用Ajax抓取另一个域的资源,就可以会出现禁止请求的情况。
- CSRF(跨站请求伪造):用户在访问银行网站时,他们很容易受到跨站请求伪造的攻击,并且能够被利用其访问其他的网站。
- token
但是保存很多的session
在服务端,一个是占用了很多存储,而且在每台服务器上都要存储session
所以出现了 token令牌
简单的token令牌比如 头部有 uid、time当前时间戳、sign签名也就是密钥和头部信息加密后得到 一个token
服务器不再保存token,服务器只保存生成token的密钥和运算过程,当生成后,保存到客户端。用户发送http请求后,携带token,服务端验签即可,通过则返回响应,不通过则让用户登录
token的验证流程如下
客户端使用用户名和密码请求登录
服务端收到请求,验证用户名和密码
验证成功后,服务端会签发一个token,再把这个token返回给客户端
客户端收到token后可以把它存储起来,比如放到cookie中
客户端每次向服务端请求资源时需要携带服务端签发的token,可以在cookie或者header中携带
服务端收到请求,然后去验证客户端请求里面带着的token,如果验证成功,就向客户端返回请求数据
Token 可以避免 CSRF 攻击
7 drf的action装饰器
- 继承viewsetmixin
- 做路由分发
8 drf的生命周期
drf的生命周期 相比 django,其中request对象是drf自己又封装的
-
请求解析阶段(Request Parsing):当客户端发送一个 HTTP 请求时,DRF 会对请求进行解析,包括对请求头、查询参数、请求体等进行解析,将请求的数据转化为 Python 对象。
-
认证和授权阶段(Authentication & Authorization):在请求解析之后,DRF 会进行认证和授权的操作,判断请求是否合法、是否具有权限等。
-
序列化阶段(Serialization):在认证和授权之后,DRF 会将请求的数据进行序列化处理,将 Python 对象转化为 JSON、XML 等格式的数据,方便客户端进行处理和展示。
-
视图调用阶段(View Calling):在序列化之后,DRF 会根据请求的 HTTP 方法和 URL 地址,调用对应的视图函数进行处理,视图函数会返回一个 Response 对象。
-
响应渲染阶段(Response Rendering):在视图调用之后,DRF 会对视图返回的 Response 对象进行渲染,将 Response 对象转化为 JSON、XML 等格式的数据,方便客户端进行处理和展示。
-
异常处理阶段(Exception Handling):如果在以上任意一个阶段出现了异常,DRF 会捕获异常并进行处理,返回相应的错误信息给客户端。
-
记录日志阶段(Logging):DRF 还提供了丰富的日志功能,可以记录请求的详细信息、异常信息等,方便开发者进行调试和排查问题。
以上就是 DRF 的生命周期,通过这些阶段,DRF 可以为我们提供快速、安全、高效的 Web API 开发体验。
9 serializer和modelserializer
在 Django Rest Framework (DRF) 中,Serializer
和 ModelSerializer
都是用来将复杂的数据类型,如 Django 的模型对象,转换成 Python 内置数据类型(如 dict,list)以便于序列化为 JSON 或其他格式的数据返回给客户端。
Serializer
和 ModelSerializer
的主要区别在于:
Serializer
可以序列化任何数据类型,而ModelSerializer
仅仅是针对 Django 的模型进行优化的。ModelSerializer
会自动根据模型定义中的字段生成序列化器字段,而Serializer
需要手动定义每一个字段。
举个例子,如果我们有一个 Django 的模型 MyModel
:
from django.db import models
class MyModel(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField()
email = models.EmailField()
那么,我们可以定义一个 MyModelSerializer
来将 MyModel
对象序列化为 JSON 格式:
from rest_framework import serializers
from .models import MyModel
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
上面的 MyModelSerializer
继承自 ModelSerializer
,并在 Meta
类中指定了要序列化的模型 MyModel
以及要序列化的字段 fields
。如果我们想要更细粒度地控制每一个字段的序列化方式,可以在 MyModelSerializer
中手动定义每一个字段。
另一方面,如果我们有一个没有对应模型的数据类型,例如:
class MyDataType:
def __init__(self, name, age, email):
self.name = name
self.age = age
self.email = email
那么我们可以使用 Serializer
来将其序列化:
class MyDataTypeSerializer(serializers.Serializer):
name = serializers.CharField(max_length=100)
age = serializers.IntegerField()
email = serializers.EmailField()
上面的 MyDataTypeSerializer
继承自 Serializer
,并手动定义了每一个字段的序列化方式。
总的来说,Serializer
适用于任何数据类型的序列化,而 ModelSerializer
主要用于对 Django 的模型进行序列化,能够快速且自动地生成序列化器字段,提高开发效率。
10.drf序列化器类支持的属性字段类型中的参数
label:文档信息,在接口文档中显示,类似模型类中的verbose_name
help_text:文档信息,和模型类中的help_text作用一致
max_value:反序列化校验允许的最大值,一般在serializers.IntergerField()中使用
min_value:反序列化校验允许的最小值,一般在serializers.IntergerField()中使用
write_only:为True时字段校验时为必传参数,只允许反序列化写入做校验,不会输出
read_only:为True时该字段值前端不能传,只会做序列化输出,定义了
read_only=True,此时前端传入了该字段值,校验器不会做校验,传入的值也不会入库,而是以空字符串入库,而且会影响后续的数据入库,报错 "Duplicate entry '' for key 'name'"。
required:为True时指定该字段为必传字段
default:指定字段不传值时自动设置默认值入库
allow_null:是否允许该字段为null,对应models中也要定义null=True才能使用
allow_blank:是否允许该字段为空字符串,对应models中也要定义null=True才能使用
format:格式化输出serializers.DateTimeField()字段,
如:format='%Y年%m月%d日 %H:%M:%S'
四、flask
1 flask的请求流程
① 应用程序初始化
Flask 应用程序启动时,它会执行一次初始化,包括创建 Flask 实例、加载配置、注册插件等
② 请求处理
请求来了
`app.run()`结果就是执行app加括号--> `app()`--> Flask类产生对象,则执行 `Flask.__call__`方法--> `self.wsgi_app(environ, start_response)`
就会根据url和http方法,找到对应的视图函数
中间还 可以执行对应的 请求拓展 等等,包括flask自己包装了 local对象,可以兼容线程、协程等,不会使得数据在不同的线程中错乱
③ 视图函数返回响应对象
④ 客户端收到后 进行解析
五、mysql
1 mysql的默认引擎, innodb和myisam的区别
默认引擎:
-
5.5版本之前为myisam,存储数据库快,但是不支持行锁、事务等功能,安全性低
-
5.5版本之后为innoDB,支持事务、行锁、外键等操作,存储数据没有myisam块,但是安全性高
-
myisam单独将索引列出来称为文件,所以其存储快,innodb没有
事务 transactions:
往通俗的讲就是,事务就是一个整体,里面的内容要么都执行成功,要么都不成功。
行锁 row-level locking:对一行行的数据进行加锁,同一时间点只能有一个人去操作这个数据
外键 foreign keys:建立表的关系
2 orm优化查询
① 使用索引来提高查询性能。
② 使用缓存来避免重复查询
③ 使用select_related()或prefetch_related()方法来优化数据库查询,避免在循环中查询数据库
④ 使用values()或values_list()方法来只查询需要的字段
⑤ distinct()方法来去重查询结果
⑥ defer()或only()方法来延迟加载或限制查询字段
- defer()方法可以将某些字段延迟加载,只在需要时才从数据库中加载
- only()方法可以限制查询结果中的字段,只加载需要的字段
使用索引来提高查询性能。
索引可以加快查询速度,并减少数据库负载。可以在需要查询的字段上使用索引,以提高查询性能。
使用缓存来避免重复查询。
缓存可以将查询结果缓存到内存中,以避免重复查询。可以使用Django的缓存框架来实现缓存功能。
以上是一些常见的Django ORM优化技巧,可以帮助提高数据库查询性能。在实际应用中,需要根据具体情况选择合适的优化方法。
1 使用select_related()或prefetch_related()方法来优化数据库查询。
select_related()方法可以使用外键关联的信息来一次性查询相关的对象,并减少查询次数。prefetch_related()方法则可以在使用ManyToManyField或ForeignKey关联的对象上使用,以减少查询次数并提高性能。
2 使用values()或values_list()方法来只查询需要的字段。
values()方法返回一个字典,包含查询结果中指定字段的值。values_list()方法返回一个元组列表,其中每个元组都包含查询结果中指定字段的值。这两种方法可以减少查询结果的大小,从而提高性能。
使用annotate()方法来聚合查询结果。
annotate()方法可以对查询结果进行聚合操作,如计算平均值、最大值等。使用聚合操作可以减少查询结果的数量,并提高性能。
使用distinct()方法来去重查询结果。
distinct()方法可以去重查询结果,并减少查询结果的数量。这可以提高查询性能并减少数据库负载。
使用defer()或only()方法来延迟加载或限制查询字段。
defer()方法可以将某些字段延迟加载,只在需要时才从数据库中加载。only()方法可以限制查询结果中的字段,只加载需要的字段。这两种方法可以减少查询结果的大小,并提高性能。
避免在循环中查询数据库。
在循环中查询数据库会导致大量的查询,从而降低性能。如果需要在循环中查询数据库,可以考虑使用select_related()或prefetch_related()方法来优化查询。
3 数据库的优化
① 建索引
- 建立索引:索引是数据库优化中常用的一种方法,可以提高查询效率。
- 在MySQL中,可以使用CREATE INDEX语句创建索引,语法为:CREATE [UNIQUE] [FULLTEXT|SPATIAL] INDEX index_name ON table_name (column1 [ASC|DESC], column2 [ASC|DESC], ...);其中,UNIQUE用于指定索引是否唯一,FULLTEXT用于全文索引,SPATIAL用于空间索引。
- 在Redis中,可以使用SORTED SET来进行排序和查找,同时也可以使用HASH等数据结构来进行查询和聚合操作。
② 慢查询
- 慢查询:慢查询是指执行时间较长的查询语句,会对数据库的性能和响应速度产生负面影响。
- 在MySQL中,可以通过开启慢查询日志记录慢查询语句,通过分析日志来找出执行时间较长的查询语句,并进行优化。
- 在Redis中,可以使用MONITOR命令来记录Redis的所有命令请求,通过分析请求日志来找出耗时较长的操作,并进行优化。
③ 定时清理
- 定时清理:定时清理是指定期删除或清理无用或过期的数据,以减少数据库的存储空间和提高查询效率。
- 在MySQL中,可以通过DELETE语句来删除指定数据,也可以通过TRUNCATE语句清空整个表格。
- 在Redis中,可以使用过期时间来控制数据的自动删除,也可以使用LUA脚本或清理命令来删除无用数据。
4 only与defer
django的orm中,defer()
或only()
方法来延迟加载或限制查询字段
defer()
方法可以将某些字段延迟加载
,只在需要时才从数据库中加载
only()
方法可以限制查询结果中的字段
,只加载需要的字段
5 sql注入问题
(1)为什么会有sql注入的问题:
利用特殊符号的组合产生特殊含义,从而避开正常的业务逻辑,比如 用SQL语法中的 --
将密码注释掉,从而实现无密码登录等
(2)解决办法
① python中连接 mysql的话需要pymysql模块,在该模块中执行sql语句的时候 使用的execute方法,execute底层已经帮我们做好了过滤特殊符号组合产生的特殊含义的问题
而django的orm连接mysql的时候,用到了mysql-client模块,底层就用到了 pymysql模块,所以也不存在sql注入的问题
② 在flask中,操作数据库使用到了sqlalchemy,在sqlalchemy中的orm中也有execute方法,也是在底层就过滤掉了特殊符号组合产生的特殊含义的问题
6 sql语句优化
① 避免使用 select *,这样会查找很多数据,浪费了内存或者CPU资源,只要需要用到的列
② 用 union all代替union
union
关键字后,可以获取排重后的数据,以左右表为基准,展示所有数据,没有对应的数据则用null补充
union
会过滤重复的结果,排重的过程需要遍历、排序和比较,它更耗时,更消耗cpu资源
union all
不过滤重复的结果
除非是有些特殊的场景,是不允许产生重复数据的,这时可以使用union。
③ 小表驱动大表
in
适用于左边大表,右边小表。in关键字,则它会优先执行in里面的子查询语句
,然后再执行in外面的语句exists
适用于左边小表,右边大表。exists关键字,它优先执行exists左边的语句(即主查询语句)
④ 批量操作
每次远程请求数据库,是会消耗一定性能的。批量操作需要把握一个度,建议每批数据尽量控制在500以内
⑤ 多用limit,可以做分页
⑥ in中值太多
in
关键字过滤出数据,查询语句一次性可能会查询出非常多的数据,很容易导致接口超时,limit做限制,或者 少查询一点字段
⑦ 用连接查询代替子查询
子查询
和 连接查询
。mysql执行子查询时,需要创建临时表,查询完毕后,需要再删除这些临时表,有一些额外的性能消耗,这时可以改成连接查询
⑧ join的表不宜过多
⑨ 控制索引的数量
mysql使用的B+树的结构来保存索引的,在insert、update和delete操作时,需要更新B+树索引
⑩ 索引优化
走了索引,和没有走索引,执行效率差别很大
可以使用explain
命令,查看mysql的执行计划
7 mysql的约束
8 mysql隐藏主键
在mysql中一张表必须要有主键,如果没有主动构建主键,那么 innodb引擎会生成一个隐藏字段做主键,构建聚簇索引
- 因为mysql底层是用B+树的结构来保存索引的
9 SQL语句的优先级
优先级 | 关键字 | 作用 |
---|---|---|
1 | from | 指定要查询的表信息 |
2 | where | 规定查询条件,然后查询并筛选 |
3 | group by | 根据指定字段进行分组,如果没有指定字段,则整个表为一组 |
4 | having | 指定查询的条件,筛选数据(二次筛选用在where之后) |
5 | select | 指定要查询的信息 |
6 | distinct | 将数据去重 |
7 | order by | 对查询的结果进行排序 |
8 | limit |
六、redis
1 redis建立连接池的目的
当多个django进程可能会导致redis连接数较高,影响redis的性能,使用连接池可以优化Redis数据库的连接和请求处理。
它允许多个客户端在需要时共享已经建立的数据库连接,而不是每次请求都需要重新建立连接,这可以显著提高Redis的性能和可伸缩性。
连接池中的连接被维护在一个连接池中,每个连接都可以被多个客户端重用。当客户端需要与Redis交互时,它可以从连接池中获取一个连接,使用它完成请求后,将连接归还给连接池,以供其他客户端使用。
2 redis持久化
混合持久化是为了快速恢复
aof日志文件中的数据的含义:“*3”表示当前命令有三个部分,每部分都是由“$+数字”开头,后面紧跟着具体的命令、键或值。这里,“数字”表示这部分中的命令、键或值一共有多少字节。例如,“$3 set”表示这部分有 3 个字节,也就是“set”命令
七、docker
1 docker如何对已经部署上线的项目做版本更新
重新构建容器,docker会自动启动并允许新的镜像
然后把旧的容器删除掉就行了
2 dockerfile的常用命令
基础镜像(FROM):定义 Dockerfile 中构建镜像的基础镜像,用于从该基础镜像开始构建镜像。
维护者信息(MAINTAINER):定义 Dockerfile 的维护者信息。
安装软件和依赖项(RUN):定义在容器中安装软件和依赖项的命令。
容器内部的工作目录(WORKDIR):定义在容器内部设置的工作目录。
拷贝文件(COPY、ADD):将本地文件或目录复制到容器中,可以使用 COPY 或 ADD 指令。
暴露端口(EXPOSE):定义容器的对外开放的端口。
执行命令(CMD、ENTRYPOINT):定义容器启动时要执行的命令或程序。
八、git
1 git的工作流程
-
master分支:版本的分支,在该分支上,发布大的版本,这些是leader来做的
-
develop分支:develop是开发环境的分支,每个开发有自己的个人分支,我们把自己开发的内容,或者修改后的内容推上去,由leader来做分支的合并
-
test分支测试:先提交代码在test分支上,让测试去测试bug,如果有bug就返回来去修改,修改过后推到develop的个人分支上
九、rabbitMQ
1 rabbitmq的交换机的模式
direct
2 rabbitmq的消息丢失怎么做
-
1 丢失的原因
消息没有做持久化
没用完 消费者down了,那消息可能就丢失了
-
2 方法
有日志的记录,通过日志来找回
做持久化
rabbitmq有回调机制,当消费者使用成功,在让rabbitmq来删除
3 rabbitMQ消息的堆积
- 原因:消费者的消费速度 小于 生产者的生成
- 逻辑优化下 加快消费
- 多节点 启动worker来加快消费
十、rpc 远程过程调用
RPC(Remote Procedure Call) 是指远程过程调用,也就是说两台服务器 A,B 一个应用部署在 A 服务器上,想要调用 B 服务器上应用提供的函数或方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据
① 作用:为什么要用 RPC
- 【机器A用java写,机器B用go写,可以让不同进程、不同机器、不同语言的服务器之间调用】可以让不在一个进程内的组织进行通信
- 【机器A的性能不够,就可以将服务(某方法)部署在机器B上,通过rpc让机器A调用机器B 】由于计算能力需要横向扩展,需要在多台机器组成的集群上部署应用
② python实现rpc
- 1 自带的模块 SimpleXMLRPCSever 底层用的是XML
①②③④⑤⑥⑦⑧⑨⑩ ```python
9 8种数据类型的常用方法
11 字符编码理论:acki gbk unicode utf8。。原理 2的32次方 utf8是优化unicode的存储问题,英文采用一个字节,中文使用三个字节
13 线程threading模块和其中常用的方法
14 drf视图类继承那种方法 APIView 自己封装
15 genric_apiview 才能写queryset和serializer属性
1 接口
y-api
政务平台
数据库连接池的目的:
主要目的是提高应用性能,减轻数据库负载
- 提高系统响应效率:连接的初始化工作完成后,所有请求可以直接利用现有连接,避免了连接初始化和释放的开销,提高了系统的响应效率。
- 资源复用:连接可以重复利用,避免了频繁创建、释放连接引入的性能开销。在减少系统消耗的基础上,增强了系统的平稳性。
- 避免连接泄漏:连接池可根据预设的回收策略,强制回收连接,从而避免了连接资源泄漏。
双下 new 和双下 init
1 __new__ 至少要有一个参数cls,代表要实例化的类
2 __new__ 必须要有一个返回值,返回父类__new__出来的空实例
3 __init__实例化调用的时候调用,进行对象的初始化
4 __call__实例化对象调用时调用
.value 和.valuelist
1、values返回是列表套字典 [{}, {}]
2、values_list返回的是列表套元组 [(), ()]
migrations 和migrate
(1)migration文件
执行了migrations命令后,会在app目录下生成migrations文件夹,记录对应的models.py中的变化
migrations 查看表接口是否改变【是否出现新表、表字段的增减】
- 迁移后的文件:版本号+models.py中的类名+时间
- 文件中的内容:
生成了一个类 migration
dependcies属性:记录了执行迁移命令的app名称,和 在那个版本上做的更新
operations属性:记录了增加的字段、修改的字段、新建的字段等等
(2)migrate
migrate 在数据库中创建数据表
数据库分库分表
1 遇到是什么情况需要分库分表
(1)数据库的存储资源是有限的,其负载能力也是有限的,数据的大量积累肯定会导致其处理数据的能力下降;
(2)数据量越多,那么对数据的增删改查操作的开销也会越来越大,所以,当出现如上两种情况,分库分表势在必行
2 垂直分 和 水平分
(1)垂直切分
适用场景:如果是因为表的个数多而让数据多,可以按照功能划分,把联系密切的表切分出来放在同一个库中(分库);
如果表的字段太多,可以以列为出发点,将字段进行拆分(分表);
(2)水平切分
适用场景:如果是因为表中的数据量过于庞大,则可以采用水平切分,按照某种约定好的规则将数据切分到不同的数据库中;
3 mysql
mysql的话 数据量达到1000万就行
这时候的SQL耗时主要集中在磁盘IO上,数据命令缓存的概率降低,总之不好搞,如果是正常的互联网项目,提前分库分表,在前期能做的先做了,后面会省很多时间处理数据迁移的事情,数据操作比较频繁,比如订单表,可能涉及到的插入和更新操作特别频繁,特别是大并发的时候,这时如果只用一个库,对磁盘的IO和mysql的性能都是一种考验,所以要分库分表,把操作频繁的表和基本信息表分开处理,减小单个数据库的压力,同时也不影响其他基本信息的读写
如果只有一台服务器,当select很多时,update和delete会被这些select访问中的数据堵塞,等待select结束,并发性能不高,此时就要选择读写分离了 {主库负责写,从库负责读}
设计模式
1 生产者-消费者模式
消息队列是生产者消费者,一个只负责 生成消息,一个负责消费消息
redis 的List
数据类型结构提供了 blpop
、brpop
命令结合 rpush
、lpush
命令可以实现消息队列机制,
2 观察模式/发布-订阅模式
https://blog.csdn.net/w15558056319/article/details/121490953
相对其他的消息中间件,redis做消息中间件比较轻量级,但是数据准确和安全性没那么高
-
redis
reids 发布订阅模式图解
- 基于频道(Channel)的发布/订阅
redis的 subscribe命令可以让客户端订阅任意数量的频道,每当有新信息发布送到被订阅的频道时,信息就会被发送给所有订阅指定频道的 # 发布订阅是 观察者模式 :只要订阅了某个东西,这个东西发送变化,我们就能收到 发布者发布了消息,所有的订阅者都可以收到,就是生产者消费者模型(后订阅了,无法获取历史消息) # 一个客户端发送消息 publish lqz hello # 只要有订阅者,客户端发送消息,所有订阅者都能收到 # 另外两个客户端,订阅频道,等待接收消息 subscribe lqz # 查看某个频道有几个订阅者 pubsub numsub lqz # 列出活跃的频道 pubsub channels #发布订阅和消息队列 发布订阅数全收到,消息队列有个抢的过程,只有一个抢到
-
订阅者订阅频道 subscribe channel [channel ...]
-
--------------------------客户端1(订阅者) :订阅频道 --------------------- # 订阅 “meihuashisan” 和 “csdn” 频道(如果不存在则会创建频道) 127.0.0.1:6379> subscribe meihuashisan csdn Reading messages... (press Ctrl-C to quit) 1) "subscribe" -- 返回值类型:表示订阅成功! 2) "meihuashisan" -- 订阅频道的名称 3) (integer) 1 -- 当前客户端已订阅频道的数量 1) "subscribe" 2) "csdn" 3) (integer) 2 #注意:订阅后,该客户端会一直监听消息,如果发送者有消息发给频道,这里会立刻接收到消息
-
发布者发布消息 *publish channel message*
-
--------------------------客户端2(发布者):发布消息给频道 ------------------- # 给“meihuashisan”这个频道 发送一条消息:“I am meihuashisan” 127.0.0.1:6379> publish meihuashisan "I am meihuashisan" (integer) 1 # 接收到信息的订阅者数量,无订阅者返回0
-
原理:底层通过字典实现。
pubsub_channels
是一个字典类型,保存订阅频道的信息:字典的key为订阅的频道, 字典的value是一个链表, 链表中保存了所有订阅该频道的客户端
3 单例模式
定义:确保一个类最多只有一个实例,并提供一个全局访问点
目的:当类中有很多非常强大的方法,我们在程序中很多地方都需要。如果不做单例,会产生很多无用的对象浪费存储空间,那么单例模式就可以在整个程序就使用一个对象。可以节省内存空间
① 导入模块实现
在模块中生成一个实例,这样导入的时候就一直是生成的那个实例
python的模块就是天然的单例模式
② 基于元类生成的单例
通过定义一个继承type的类, 通过派生 __init__
方法,从而可以定制一个类的行为,当我们不传参的时候,会默认为单例模式;传参时则会正常产生其他实例。
用call方法实现单例,init方法不会使用
class MyMeta(type):
def __init__(cls, name, bases, dic): # 定义类MyMeta时就触发
# 事先先从配置文件中取配置来造一个Mysql的实例出来
cls.__instance = object.__new__(cls) # 产生对象
cls.__init__(cls.__instance, 'jason', 18) # 初始化对象
# 上述两步可以合成下面一步
# self.__instance=super().__call__(*args,**kwargs)
super().__init__(name, bases, dic)
def __call__(cls, *args, **kwargs): # MyMeta(...)时触发
if args or kwargs: # args或kwargs内有值
obj = object.__new__(cls)
cls.__init__(obj, *args, **kwargs)
return obj
return cls.__instance
class Mysql(metaclass=MyMeta):
def __init__(self, name, age):
self.name = name
self.age = age
obj1 = Mysql()
obj2 = Mysql() # obj1 和 obj2都是同一个实例
print(obj1.name)
print(obj2.name)
print(id(obj1), id(obj2)) # 4302991264 4302991264
obj3 = Mysql('tony', 321) # 当传进去不同的参数时,也可以产生其他对象
obj4 = Mysql('kevin', 222)
print(id(obj3), id(obj4)) # 4302990736 4302990544
③ 基于双下 new方法
基于 new方法,会使用 init方法
new方法用于在生成实例前,在生成实例前判断是否已经存在实例,存在则返回已经生成的示例,没有则返回生成的示例
class Mysql(object):
_instance = None
def __init__(self,name):
self.name = name
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = object.__new__(cls)
return cls._instance
obj = Mysql('egon')
obj1 = Mysql('jason')
print(id(obj),id(obj1))
4 装饰器模式
5 工厂模式
range
迭代器、生成器
①②③④⑤⑥⑦⑧⑨⑩ ```python
十一、APScheduler
apscheduler包含了四种组件:触发器(trigger)、作业存储(job store)、执行器(executor)、调度器(scheduler)
-
triggers触发器:
- cron定时调度:某一时刻执行
- interval:间隔调度,即每个多久执行一次
- date:定时调度,作业只会被执行一次
-
job stores作业存储:
创建Job时指定执行的函数,函数中所需参数,Job执行时的一些设置信息
作业存储器的选择有两种:一是内存,也是默认的配置;二是数据库
-
executors处理器:执行器的选择也取决于应用场景,通常默认的 ThreadPoolExecutor 已经足够好,果作业负载涉及CPU 密集型操作,那么应该考虑使用 ProcessPoolExecutor,甚至可以同时使用这两种执行器,将ProcessPoolExecutor 行器添加为二级执行器
-
schedulers:调度程序是将其余部分绑定在一起的东西;您的应用程序中通常只有一个调度程序在运行
1.工作机制
1 创建调度器:导入模块创建 scheduler对象,我们都用的是BackgroundScheduler 后台调度器
2 添加job :给scheduler添加job
① 调用 add_job() 方法,add_job() 方法返回一个 apscheduler.job.Job 实例
② 使用 scheduled_job() 装饰一个函数
3 executors:Executors负责处理作业的运行;
自我介绍
-
hdfs
-
es
jwt 认证 、二次登录
rbac
1 权限的控制??
按钮权限的控制
数据权限的控制
菜单权限的控制
2 不同用户看到不同菜单的原因
不同用户 有不同的权限, 前端控制
3 按钮权限的控制
先说什么是rbac?
用户跟角色去关联:
一 登录就返回所有权限
二 访问页面就返回对应的权限
4 不属于角色的功能,怎么给角色添加
再建一张表,用户 和权限管理,多对多的关系
5 超级管理员后分配角色,怎么不退出登录,更新权限分配
双写一致性:修改数据删缓存
一旦 超级管理员修改权限,那么就把缓存删除
1 异步任务怎么做的,异步功能的理解
2 单例模式
python中的模块就是最简单的
3 cd:是切换到你要的目录里去
ls;是显示文件夹里面有些什么文件
mkdir;是创建文件夹
touch:是创建文件
mv;是移动某个文件到对应的文件夹下
vim:是用来做文本编辑的
tree;是显示目录层级
echo:相当于python的print,是输出的打印的意思
rm:是删除
敏捷开发
需求分析---》设计---》只设计一个板块---》开发(2周)---》交给测试---》运维上线(测试环境)
-设计---》只设计一个板块---》开发(2周)---》交给测试---》运维上线(测试环境)
更具URL确定哪个页面,
标签:__,面试题,请求,django,Celery,查询,方法 From: https://www.cnblogs.com/DuoDuosg/p/17389298.html