1. 什么是wsgi?
WSGI 是 “Web Server Gateway Interface” 的缩写,它是一种用于 Python Web 应用程序和 Web 服务器之间通信的标准接口
。它定义了一组规则和约定,使 Web 服务器能够与任何符合 WSGI 规范的 Python Web 应用程序进行交互。
###\ WSGI 的作用
WSGI 的作用是将 Web 服务器与 Python Web 应用程序解耦,使它们能够独立开发和部署。这使得 Web 服务器可以支持多种不同的 Python Web 框架,而无需修改其代码。
###\ WSGI 的工作原理
WSGI 的工作原理如下:
- Web 服务器接收到一个 HTTP 请求。
- Web 服务器将请求传递给 WSGI 应用程序。
- WSGI 应用程序处理请求并生成一个 HTTP 响应。
- Web 服务器将响应返回给客户端。
2. asgi和wsgi的异同
WSGI和ASGI,都是基于Python设计的网关接口
(Gateway Interface,GI)
WSGI是基于http协议模式开发的,不支持websocket
ASGI不仅支持当前的web开发中的一些新的协议标准,同时ASGI支持原有模式和Websocket
的扩展,即ASGI是WSGI的扩展。
网关接口(Gateway Interface,GI)
网关接口是一个定义了 Web 服务器
和 Web 应用程序
之间通信方式
的规范。只有Web应用程序都实现了网关接口规范后,双方的通信才能顺利完成。常见的网关接口协议:CGI、FASTAPI、WSGI、ASGI。
web服务器 && web应用程序
Web 服务器
Web 服务器 是一个软件程序,它运行在计算机上,用于处理来自客户端(例如浏览器)的 HTTP 请求,并向客户端发送响应。
Web 服务器的主要功能包括:
- 接收来自客户端的 HTTP 请求
- 处理 HTTP 请求并解析 URL
- 查找请求的资源(例如 HTML 文件、图像文件)
- 将资源的内容发送给客户端
- 处理 HTTP 头和状态码
- 处理 Cookie 和会话
Web 应用程序
Web 应用程序 是一个运行在 Web 服务器上的软件程序,它用于处理来自客户端的 HTTP 请求并生成动态内容。Web 应用程序通常使用编程语言(例如 Python、PHP、Java)编写,并使用数据库来存储数据。
Web 应用程序的主要功能包括:
- 处理来自客户端的 HTTP 请求
- 生成动态内容(例如 HTML 页面、JSON 数据)
- 访问数据库
- 处理用户输入
- 处理会话
Web 服务器和 Web 应用程序的区别
特征 | Web 服务器 | Web 应用程序 |
---|---|---|
功能 | 处理 HTTP 请求并发送静态内容 | 处理 HTTP 请求并生成动态内容 |
编程语言 | C、C++ | Python、PHP、Java |
数据库 | 通常不使用 | 通常使用 |
可扩展性 | 更高 | 更低 |
示例 | Apache、Nginx、IIS | Django、Flask、WordPress |
3. django请求的生命周期?
- 当用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务端
- 服务端的wsgiref模块接收用户请求并将请求进行初次封装
- 将请求交给Django的中间件
- 通过中间件之后将请求交给url,根据浏览器发送的不同url去匹配不同的视图函数
- 视图函数根据业务逻辑调用数据库获取相应的数据,然或根据模板渲染页面
- 视图函数将响应的页面依次通过中间件
- 到达wsgi,封装数据后反馈给客户端
4. 中间件
中间件的定义
中间件是一个用来处理Django的请求和响应
的框架级别的钩子
。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。
说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。
中间件的五个方法
process_request(self,request)
:请求进来时,权限认证process_view(self, request, view_func, view_args, view_kwargs)
:路由匹配之后,能够得到视图函数process_template_response(self,request,response)
:模板渲染时执行process_exception(self, request, exception)
:异常时执行process_response(self, request, response)
:请求有响应时执行
以上方法的返回值可以是None或一个HttpResponse对象。如果是None,则继续按照Django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。
Django中间件
中间件执行流程
请求到达中间件之后,先按照正序
执行每个注册中间件的process_reques方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法,将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。
process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数,按正序
执行。假如中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。
process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序
。总结所有的执行流程如下:
注意:这里的正序指的是按照MIDDLEWARE中的注册顺序从前到后顺序执行的(在settings.py里面设置中 从下到上的顺序)。
5. 什么是CSRF,Django如何解决?
CSRF概念
CSRF(cross-site request forgery),简称跨站请求伪造。,攻击者可以利用用户的登录状态,在用户不知情的情况下,以用户的身份向网站发送恶意请求。
- 受害者登录a.com,并保留了登录凭证(Cookie)。
- 攻击者引诱受害者访问了b.com。
- b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie。
- a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求。
- a.com以受害者的名义执行了act=xx。
- 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作。
Django中的CSRF实现机制
django通过django.middleware.csrf.CsrfViewMiddleware
这个中间层来完成。
Django预防CSRF攻击的方法是在用户提交的表单中加入一个csrftoken的隐含值,这个值和服务器中保存的csrftoken的值相同,这样做的原理如下:
1、在用户访问django的可信站点时,django反馈给用户的表单中有一个隐含字段csrftoken,这个值是在服务器端随机生成的,每一次提交表单都会生成不同的值
2、当用户提交django的表单时,服务器校验这个表单的csrftoken是否和自己保存的一致,来判断用户的合法性
3、当用户被csrf攻击从其他站点发送精心编制的攻击请求时,由于其他站点不可能知道隐藏的csrftoken字段的信息这样在服务器端就会校验失败,攻击被成功防御
(每一次提交表单都会生成一个新的csrftoken,所以就算恶意获得一次token,再执行另一次表单提交时,也会校验失败)
6. Django如何实现websocket
Django使用Channels实现WebSocket的方法
官方文档
Django 的核心组件
对象关系映射(ORM)
:它将面向对象编程语言(如 Python)中的对象与关系型数据库(如 MySQL)中的表进行映射。ORM 允许使用面向对象的方式来操作数据库,而无需编写复杂的 SQL 语句。
2. URL分发器
:定义 URL 模式和视图之间的映射的 Python 模块。它允许将 URL 映射到特定的视图函数,以便处理不同的请求
3. 视图
:视图是用来处理 HTTP 请求和生成响应的函数。
4. 模板
:用于将模板文件转换成 文件,并在浏览器上显示
5. 中间件
:中间件是用来拦截和修改 HTTP 请求和响应的类。它们可以用于各种目的,例如身份验证、授权、缓存和日志记录。
6. 管理站点
:管理站点是一个基于 Web 的界面,允许管理模型数据。它提供了一个用户友好的界面来创建、读取、更新和删除模型实例。
7. 表单序列化及验证系统 (Form):用于 表单和数据库存储的数据之间的转换
7. FBV & CBV
FBV (Function-Based View) 函数式视图 是 Django 中的一种视图类型,它使用 Python 函数来处理 HTTP 请求和生成响应。FBV 通常用于编写简单的视图,例如登录视图或注销视图。
CBV (Class-Based View) 类式视图 是 Django 中另一种视图类型,它使用 Python 类来处理 HTTP 请求和生成响应。CBV 通常用于编写更复杂的视图,例如列表视图或详细视图。
FBV 和 CBV 的主要区别在于:
- 代码组织: FBV 的代码通常分散在多个函数中,而 CBV 的代码通常组织在一个类中。
- 可重用性: CBV 通常比 FBV 更可重用,因为可以将 CBV 继承到其他 CBV 中,并重用其代码。
- 可测试性: CBV 通常比 FBV 更可测试,因为可以使用单元测试框架来测试 CBV 的方法。
8. 如何给CBV的程序添加装饰器?
在类视图中使用为函数视图准备的装饰器时,不能直接添加装饰器,需要使用method_decorator
将其转换为适用于类视图方法的装饰器。
在URL上添加
# urls.py
urlpatterns = [
path("login/",views.Mydecorator(views.MyView.as_view())),
]
在类上添加,name=“函数名称”
@method_decorator(Mydecorator,name="post")
@method_decorator(Mydecorator,name="get")
class MyView(View):
def get(self,request):
return HttpResponse("get请求")
def post(self,request):
return HttpResponse("post请求")
在函数上添加
class MyView(View):
@method_decorator(Mydecorator)
def get(self,request):
return HttpResponse("get请求")
def post(self,request):
return HttpResponse("post请求")
9. 列举django orm 中所有的方法
Django QuerySet 方法表格
方法 | 描述 |
---|---|
all() | 查询所有结果 |
filter(**kwargs) | 它包含了与所给筛选条件相匹配的对象。获取不到返回None |
get(**kwargs) | 返回与所给筛选条件相匹配的对象,返回结果有且只有一个。获取不到会抱错#如果符合筛选条件的对象超过一个或者没有都会抛出错误 |
exclude(**kwargs) | 它包含了与所给筛选条件不匹配的对象 |
order_by(*field) | 对查询结果排序 |
reverse() | 对查询结果反向排序 |
count() | 返回数据库中匹配查询(QuerySet)的对象数量 |
first() | 返回第一条记录 |
last() | 返回最后一条记录 |
exists() | 如果QuerySet包含数据,就返回True,否则返回False |
values(*field) | 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系 model的实例化对象,而是一个可迭代的字典序列 |
values_list(*field) | 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 |
distinct() | 从返回结果中剔除重复纪录 |
bulk_create() | 批量创建数据 |
Django ORM 方法代码示例
1. all()
方法
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=255)
author = models.CharField(max_length=255)
# 查询所有图书
books = Book.objects.all()
# 打印所有图书的标题
for book in books:
print(book.title)
2. filter()
方法
# 查询标题为 "Django" 的图书
books = Book.objects.filter(title="Django")
# 打印所有图书的标题和作者
for book in books:
print(f"{book.title} by {book.author}")
3. get()
方法
# 获取主键为 1 的图书
book = Book.objects.get(pk=1)
# 打印图书的标题
print(book.title)
4. exclude()
方法
# 查询标题不为 "Django" 的图书
books = Book.objects.exclude(title="Django")
# 打印所有图书的标题
for book in books:
print(book.title)
5. order_by()
方法
# 按标题升序排序图书
books = Book.objects.order_by("title")
# 打印所有图书的标题
for book in books:
print(book.title)
6. reverse()
方法
# 按标题降序排序图书
books = Book.objects.order_by("title").reverse()
# 打印所有图书的标题
for book in books:
print(book.title)
7. count()
方法
# 统计所有图书的数量
count = Book.objects.count()
# 打印图书数量
print(f"Total books: {count}")
8. first()
方法
# 获取第一个图书
book = Book.objects.first()
# 打印图书的标题
print(book.title)
9. last()
方法
# 获取最后一个图书
book = Book.objects.last()
# 打印图书的标题
print(book.title)
10. exists()
方法
# 检查标题为 "Django" 的图书是否存在
exists = Book.objects.filter(title="Django").exists()
# 打印结果
print(f"Book with title 'Django' exists: {exists}")
11. values()
方法
# 获取所有图书的标题和作者
values = Book.objects.values("title", "author")
# 打印所有图书的标题和作者
for value in values:
print(f"{value['title']} by {value['author']}")
12. values_list()
方法
# 获取所有图书的标题和作者
values_list = Book.objects.values_list("title", "author")
# 打印所有图书的标题和作者
for value in values_list:
print(f"{value[0]} by {value[1]}")
13. distinct()
方法
# 剔除重复的作者
authors = Book.objects.values_list("author", flat=True).distinct()
# 打印所有作者
for author in authors:
print(author)
10. select_related和prefetch_related的区别?
select_related
select_related通过多表join关联查询
,一次性获得所有数据,通过降低数据库查询次数来提升性能,但关联表不能太多,因为join操作本来就比较消耗性能。
# 获取id=1的文章对象同时,获取其相关username信息
Article.objects.select_related('username').get(id=1)
# 获取id=1的文章对象同时,获取其相关作者名字信息
Article.objects.select_related('username__username').get(id=1)
# 获取id=1的文章对象同时,获取其相关tag和相关作者名字信息。下面方法等同。
# 方式一:
Article.objects.select_related('tag', 'username__username').get(id=1)
# 方式二:
Article.objects.select_related('tag').select_related('username__username').get(id=1)
# 使用select_related()可返回所有相关主键信息。all()非必需。
Article.objects.all().select_related()
# 获取Article信息同时获取username信息。filter方法和selected_related方法顺序不重要。
# 方式一:
Article.objects.filter(tag__gt=3).select_related('username')
# 方式二:
Article.objects.select_related('username').filter(tag__gt=3)
prefetch_related
prefetch_related不在数据库中进行连接,而是在python中连接
,不创建带join的SQL语句
articles = Article.objects.all().select_related('category').prefecth_related('tags')
# 文章列表及每篇文章的tags对象名字信息
Article.objects.all().prefetch_related('tags__name')
# 获取id=13的文章对象同时,获取其相关tags信息
Article.objects.prefetch_related('tags').get(id=13)
# 获取文章列表及每篇文章相关的名字以P开头的tags对象信息
Article.objects.all().prefetch_related(
Prefetch('tags', queryset=Tag.objects.filter(name__startswith="P"))
)
# 文章列表及每篇文章的名字以P开头的tags对象信息, 放在article_p_tag列表
Article.objects.all().prefetch_related(
Prefetch('tags', queryset=Tag.objects.filter(name__startswith="P")),
to_attr='article_p_tag'
)
- 对与单对单或单对多外键ForeignKey字段,使用select_related方法
- 对于多对多字段和反向外键关系,使用prefetch_related方法
- 两种方法均支持双下划线指定需要查询的关联对象的字段名
select_related和prefetch_related的用法与区别
select_related和prefetch_related的使用