首页 > 其他分享 >面试题2

面试题2

时间:2023-05-10 20:57:34浏览次数:46  
标签:__ 面试题 请求 django Celery 查询 方法

目录

一、python

1 数据类型

数据类型:整形、浮点型、字符串、布尔值、列表、字典、集合、元组

2可变、不可变

可变:列表、字典、集合
不可变:数字、字符串、元组

可变不可变指的是内存中的那块空间是否可以被改变

3装饰器、迭代器、生成器

① 装饰器:

在不改变原有函数代码的基础上,在函数执行前后进行自定义操作。装饰器本质是一个闭包函数,就是定义在函数内部用到了外部作用域变量的函数,叫做闭包函数

应用:

  • 1 给一些功能【函数】添加记录日志的功能,记录函数的运行时间等等
  • 2 比如说flask中的路由就是通过装饰器来映射的,flask中的请求拓展也是通过装饰器操作的
  • 3 django中的 权限装饰器、用户登录装饰器等等

【类装饰器】

① 装饰器是类

可以用 __init____call__来实现给被装饰的函数,添加新的属性和方法等等,主要就是在 __call__中去添加执行函数前后的逻辑代码

② 给类添加的装饰器

比如在sqlalchemy中的 :

scoped_session的对象,没有session中的方法,比如addcommit等等,但是可以使用加在类上的装饰器,给这个类增加属性或者方法

这样scoped_session的对象,就可以使用Session类中的方法

image-20230410183500441

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 可以一站式搞定,将在后面展开讲

img

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.user获取当前登录对象

    如果没登录获取到的是 匿名对象 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路由和视图函数之间的映射关系。

② 视图层:

  1. django.views.View: 这是所有视图的基类,用于处理HTTP请求并返回HTTP响应。

  2. django.contrib.auth.models.User: 这是Django自带的用户模型类,用于处理用户认证和授权。

  3. django.forms.Form: 这是所有表单的基类,用于验证和处理用户提交的数据。

③ 模型层orm

  1. django.db.models.Model: 这是所有Django模型的基类,用于定义数据库中的数据模型。
  2. django.middleware.MiddlewareMixin: 这是中间件的基类,用于处理HTTP请求和响应,类似于拦截器或过滤器。

④ 中间件:

django.middleware.MiddlewareMixin: 这是中间件的基类,用于处理HTTP请求和响应,类似于拦截器或过滤器。

①②③④⑤⑥⑦⑧⑨⑩ ```python

三、drf

1 restful规范

① 简介

一种定义 web api接口的设计风格与平台语言框架无关,认为后端就是提供数据资源的

并且对于数据资源通过post 、delete、get、update对应增删查改

② 内容

  1. 需要考虑安全的数据用https来传输
  2. 路径中带api标志
  3. 路径中带版本标志
  4. 数据就是资源,接口用名词表示
  5. 资源操作 由请求方法来决定
  6. 在请求地址中带过滤条件
  7. 规定了响应状态码
  8. 返回数据中带错误信息
  9. get返回所有数据为列表单个为对象,post新增返回对象,put修改返回完整对象,delete删除返回空文档
  10. 响应数据中带链接

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的异常处理为Http404PermissionDenied

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

  • 基于服务器的验证出现的问题
  1. Seesion:每次认证用户发起请求时,服务器需要去创建一个记录来存储信息。当越来越多的用户发请求时,内存的开销也会不断增加。
  2. 可扩展性:在服务端的内存中使用Session存储登录信息,占用资源的问题
  3. CORS(跨域资源共享):当我们需要让数据跨多台移动设备上使用时,跨域资源的共享会是一个让人头疼的问题。在使用Ajax抓取另一个域的资源,就可以会出现禁止请求的情况。
  4. 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自己又封装的

  1. 请求解析阶段(Request Parsing):当客户端发送一个 HTTP 请求时,DRF 会对请求进行解析,包括对请求头、查询参数、请求体等进行解析,将请求的数据转化为 Python 对象。

  2. 认证和授权阶段(Authentication & Authorization):在请求解析之后,DRF 会进行认证和授权的操作,判断请求是否合法、是否具有权限等。

  3. 序列化阶段(Serialization):在认证和授权之后,DRF 会将请求的数据进行序列化处理,将 Python 对象转化为 JSON、XML 等格式的数据,方便客户端进行处理和展示。

  4. 视图调用阶段(View Calling):在序列化之后,DRF 会根据请求的 HTTP 方法和 URL 地址,调用对应的视图函数进行处理,视图函数会返回一个 Response 对象。

  5. 响应渲染阶段(Response Rendering):在视图调用之后,DRF 会对视图返回的 Response 对象进行渲染,将 Response 对象转化为 JSON、XML 等格式的数据,方便客户端进行处理和展示。

  6. 异常处理阶段(Exception Handling):如果在以上任意一个阶段出现了异常,DRF 会捕获异常并进行处理,返回相应的错误信息给客户端。

  7. 记录日志阶段(Logging):DRF 还提供了丰富的日志功能,可以记录请求的详细信息、异常信息等,方便开发者进行调试和排查问题。
    以上就是 DRF 的生命周期,通过这些阶段,DRF 可以为我们提供快速、安全、高效的 Web API 开发体验。

9 serializer和modelserializer

在 Django Rest Framework (DRF) 中,SerializerModelSerializer 都是用来将复杂的数据类型,如 Django 的模型对象,转换成 Python 内置数据类型(如 dict,list)以便于序列化为 JSON 或其他格式的数据返回给客户端。

SerializerModelSerializer 的主要区别在于:

  1. Serializer 可以序列化任何数据类型,而 ModelSerializer 仅仅是针对 Django 的模型进行优化的。
  2. 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数据类型结构提供了 blpopbrpop 命令结合 rpushlpush 命令可以实现消息队列机制,

image-20230504180215543

2 观察模式/发布-订阅模式

https://blog.csdn.net/w15558056319/article/details/121490953

相对其他的消息中间件,redis做消息中间件比较轻量级,但是数据准确和安全性没那么高

  • redis

    reids 发布订阅模式图解

    • 基于频道(Channel)的发布/订阅

    image-20230504175739515

    
    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

相关文章

  • 面试题之GIL全局解释器锁和互斥锁(详细后面补)
    目录一、全局解释器锁(GIL)什么是(GIL)全局解释器锁?详细概念1、什么是全局解释器锁2、全局解释器锁的好处全局解释器的缺点4、GIL的作用:什么是互斥锁?概念代码解释二、同步锁1、什么是同步锁?2、为什么用同步锁?3、怎么使用同步锁?4、同步锁的所用:三、死锁1、什么是死锁?2、死锁产生的必要......
  • 百度最新面试题集锦
    1、实现一个函数,对一个正整数n,算得到1需要的最少操作次数。操作规则为:如果n为偶数,将其除以2;如果n为奇数,可以加1或减1;一直处理下去。例子:func(7)=4,可以证明最少需要4次运算n=7n-16n/23n-12n/21要求:实现函数(实现尽可能高效)intfunc(unsignintn);n为输入,返回最小的运算次......
  • 【前端】-近期面试题
    setupsetup中的代码与普通的 <script> 只在组件被首次引入的时候执行一次不同,<scriptsetup> 中的代码会在每次组件实例被创建的时候执行。所以,任何在 <scriptsetup> 声明的顶层的绑定(包括变量,函数声明,以及import导入的内容)都能在模板中直接使用。有方法通过impo......
  • 一道Promise面试题,并对比向其代码中添加await关键字后的变化
    标准代码:(function(){console.log(1);window.setTimeout(()=>{console.log(2);},100);newPromise((resolve)=>{console.log(3);resolve();}).then(()=>{console.log(4);......
  • 面试题之数据库存储引擎
    目录复习老师讲得什么是存储引擎?如何查看常见存储引擎的方式?需要了解的四个存储引擎了解不同存储引擎底层文件个数补充了解详细概念数据库引擎的类型1、InnoDB引擎2、ISAM引擎3、MYISAM引擎4、MEMORY存储引擎5、HEAP引擎6、ARCHIVE引擎7、BERKLEYDB引擎InnoDB与MyISAM差别ACID复......
  • 前端面试题-常见的水平垂直居中实现方案
    方案一:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><metaname="viewport"content="w......
  • #yyds干货盘点# LeetCode面试题:不同的二叉搜索树 II
    1.简述:给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。 示例1:输入:n=3输出:[[1,null,2,null,3],[1,null,3,2],[2,1,3],[3,1,null,null,2],[3,2,null,1]]示例2:输入:n=1输出:[[1]]2.代......
  • Java后端真实、靠谱、强大的面试题网站:面试梯
    ​ 本文分享一个给力的Java后端面试题网站:面试梯。网址:https://offer.skyofit.com这套题真实、高频、全面、有详细答案、保你稳过面试,让你成为offer收割机。题目包括:Java基础、多线程、JVM、数据库、Redis、Shiro、Spring、SpringBoot、MyBatis、MQ、ELK、分布式、SpringCloud......
  • Mysql面试题
    1.Mysql基础1、from子句组装来自不同数据源的数据;2、where子句基于指定的条件对记录行进行筛选;3、groupby子句将数据划分为多个分组;4、使用聚集函数进行计算;5、使用having子句筛选分组;6、计算所有的表达式;7、select的字段;8、使用orderby对结果集进行排序。SQL语言不同......
  • Python实操面试题
    1、一行代码实现1--100之和#利用sum()函数求和sum(range(1,101))2、如何在一个函数内部修改全局变量#利用global在函数声明修改全局变量a=5deffunc(): globalaa=10func()print(a)#结果:103、列出5个python标准库'''os:提供了不少与操作系统......