文章目录
- 面试题一:什么是wsgi?
- 面试题二:描述一下django请求的生命周期?
- 面试题三:谈谈django的orm优化操作
- 面试题四:列举django中间件的5个方法?以及django中间件的应用场景?
- 面试题五:django中如何实现orm表中添加数据时创建一条日志记录?
- 面试题六:django缓存如何设置?
- 使用缓存的五种情况
- 面试题七:对cookies与session的了解?他们能单独用吗?
个人主页:道友老李
欢迎加入社区:道友老李的学习社区
面试题一:什么是wsgi?
全称 Python Web Server Gateway Interface,指定了web服务器和Python web应用或web框架之间的标准接口,以提高web应用在一系列web服务器间的移植性。
详细的说:
- WSGI是一套接口标准协议/规范;
- 是作用在Web服务器和Python Web应用程序之间,用于通信;
- 目的是制定标准,以保证不同Web服务器可以和不同的Python程序之间相互通信
为什么需要wsgi呢?
当请求时Web服务器需要和web应用程序进行通信,但是web服务器有很多种啊,Python web应用开发框架也对应多种啊,所以WSGI应运而生,定义了一套通信标准。试想一下,如果不统一标准的话,就会存在Web框架和Web服务器数据无法匹配的情况,那么开发就会受到限制,这显然不合理的。
面试题二:描述一下django请求的生命周期?
- 1、用户请求进来先走到 wsgi 然后将请求交给 django的中间件
- 2、穿过django中间件(方法是process_request) 路由匹配
- 3、路由匹配成功之后就执行相应的 :视图函数
- 4、在视图函数中可以调用orm做数据库操作
- 5、根据模板文件 ,在后台进行模板渲染
- 6、模板渲染完成之后就响应结果,再把这个响应结果经过所有中间件(方法:process_response) 和wsgi 返回给用户
面试题三:谈谈django的orm优化操作
-
1、尽可能的使用only与defer:Defer方法的用途是查询数据库时跳过指定的字段,only方法是指定需要载入的字段。从而节省空间。一行数据可能没啥关系,但数据很多时,节省的内存空间不可忽视。
-
2、select_related和prefetch_related都是做连表查询的:prefetch_related是查询了每个表,然后在语言层面进行连接,而select_related是通过join方法进行数据库的连接,所以select_related在查询的时候是比prefetch_related效率要高的,但是prefetch_related可以进行多对多的查询。
总结:可以理解为外键使用select_related,多对多使用prefetch_related。 -
3、在任何位置使用QuerySet.exists()或者QuerySet.count()都会导致额外的查询。
-
4、不要做无所谓的排序,排序并非没有代价,每个排序的字段都是数据库必须执行的操作。
-
5、如果要插入多条数据,则使用bulk_create来批量插入,减少sql执行的数量。
-
6、使用QuerySet.Iterator迭代大数据,要么使用分页。
-
7、复杂的查询(子查询),尽量采用原生SQL查询。
# 一、原生SQL ---> connectionfrom django.db import connection, connections
cursor = connection.cursor() # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
row = cursor.fetchone() # fetchall()/fetchmany(..)# 二、extra
def extra(self, select=None, where=None, params=None, tables=None, order_by=None,
select_params=None)# 构造额外的查询条件或者映射,如:子查询Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"},select_params=(1,))Entry.objects.extra(where=['headline=%s'], params=['Lennon'])Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])# 三、 raw函数
def raw(self, raw_query, params=None, translations=None, using=None):# 执行原生SQLmodels.UserInfo.objects.raw('select * from userinfo')# 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名models.UserInfo.objects.raw('select id as nid,name as title from 其他表')# 为原生SQL设置参数models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])# 将获取的到列名转换为指定列名name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)# 指定数据库models.UserInfo.objects.raw('select * from userinfo', using="default")
面试题四:列举django中间件的5个方法?以及django中间件的应用场景?
process_request(self,request) 先走request 通过路由匹配返回
process_view(self, request, callback, callback_args, callback_kwargs) 再返回执行view
process_template_response(self,request,response) 当视图函数的返回值,process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法
process_exception(self, request, exception) 这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。
process_response(self, request, response)
面试题五:django中如何实现orm表中添加数据时创建一条日志记录?
Django 中的一些常用内置信号。与Model 相关的信号,这些信号由各个 Model 的方法发送,如 save、__init__等,且通常都是成对出现的,如下所示:
- django.db.models.signals.pre_init 与 django.db.models.signals.post_init:实例化模型之前与之后发送的信号,即在__init__方法执行的前后。
- django.db.models.signals.pre_save 与 django.db.models.signals.post_save:模型实例保存(执行save方法)前后发送的信号。
- django.db.models.signals.pre_delete 与 django.db.models.signals.post_delete:模型实例或 QuerySet 的 delete() 方法执行前后发送的信号。
- django.db.models.signals.m2m_changed:模型实例中的ManyToManyField(多对多)字段被修改(add,remove,clear)的前后发送的信号。
面试题六:django缓存如何设置?
django中提供了5种缓存后端:
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
安装第三方组件支持redis:
- django-redis组件
只需要修改django项目的配置文件settings.py,即可实现不同缓存方式的切换。
# 一、内存CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', # 指定缓存使用的引擎'LOCATION': 'unique-snowflake', # 写在内存中的变量的唯一值 'TIMEOUT': 300, # 缓存超时时间(默认为300秒,None表示永不过期)'OPTIONS': {'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)}}
}
# 二、文件缓存CACHES = {'default': {'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', # 指定缓存使用的引擎'LOCATION': '/var/tmp/django_cache', # 指定缓存的路径'TIMEOUT': 300, # 缓存超时时间(默认为300秒,None表示永不过期)'OPTIONS': {'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)}}
}
# 三、数据库缓存
CACHES = {'default': {'BACKEND': 'django.core.cache.backends.db.DatabaseCache', # 指定缓存使用的引擎'LOCATION': 'cache_table', # 数据库表 'OPTIONS': {'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)}}
}# python manage.py createcachetable 创建缓存表
# 四、Memcached缓存# Memcached是Django原生支持的缓存系统.要使用Memcached,需要下载Memcached的支持库python-memcached或pylibmc.CACHES = {'default': {'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', # 指定缓存使用的引擎'LOCATION': '192.168.10.100:11211', # 指定Memcache缓存服务器的IP地址和端口'OPTIONS': {'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)}}
}
# 五、 Redis缓存
CACHES = {"default": {"BACKEND": "django_redis.cache.RedisCache", # 缓存类型"LOCATION": "127.0.0.1:6379", # ip端口"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient", #"CONNECTION_POOL_KWARGS": {"max_connections": 100} # 连接池最大连接数# "PASSWORD": "密码",}}
}
使用缓存的五种情况
第一:全站使用缓存,用户的请求通过中间件,经过一系列的认证等操作,如果请求的内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户# 当返回给用户之前,判断缓存中是否已经存在,如果不存在,则UpdateCacheMiddleware会将缓存保存至Django的缓存之中,以实现全站缓存# 请求来了,是从上到下入走中间件;响应的时候是从下到上走中间件。因此,获取页面放在最后,保存页面放最前面
MIDDLEWARE = ['django.middleware.cache.UpdateCacheMiddleware', # 响应HttpResponse中设置几个headers'django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware','django.middleware.cache.FetchFromCacheMiddleware', # 用来缓存通过GET和HEAD方法获取的状态码为200的响应
]CACHE__MIDDLEWARE_SECONDS=15 # 设定超时时间为15秒
第二:视图中使用缓存,视图缓存是将视图函数执行过程中生成缓存数据,主要以装饰器的形式来实现。装饰器有三个参数:timeout、cache和#key_prefix,参数timeout是必选参数,其余两个是可选参数。
from django.shortcuts import render
from django.views.decorators.cache import cache_page
# cache与全站缓存CACHE_MIDDLEWARE_ALIAS相同# key_prefix与全站缓存CACHE_MIDDLEWARE_KEY_PREFIX相同
@cache_page(10, cache='default', key_prefix='mysite')
def index(request):return render(request,"index.html")
第三:路由缓存,作用与视图缓存相同,但两者是有区别的。如有两个URL同时指向一个视图函数,分别访问这两个URL时,路由缓存会判断URL是否生成缓存而决定是否执行视图函数。
from django.conf.urls import url
from app1 import views
from django.views.decorators.cache import cache_pageurlpatterns = [url(r'^index/', cache_page(10,cache='default', key_prefix='mysite')(views.index)),
第四:模板页面缓存
对模板某部分的数据设置缓存,常用于模板内容变动较少的情况。通过Django的缓存标签实现的,缓存标签只支持两个参数:timeout和key_prefix,以index.html为例实现模板缓存
将按给定的时间缓存包含块中的内容。它最少需要两个参数:缓存时间(以秒为单位);给缓存片段起的名称,该名称将被视为是字符串,而不是变量。设定超时时间为10秒, 给缓存模板片段起名为 “time”
第五:手动缓存
如果不想为一个方法(页面)进行缓存,只想缓存某个字段的话,可以 手动缓存
from django.core.cache import cache
from django.http.response import HttpResponse
import timedef index(request):print('视图函数被调用')result = cache.get('result')if not result:result = 0for i in range(10):result += itime.sleep(0.5)cache.set('result', result, 10)ctime = time.strftime('%H:%M:%S', time.localtime())return HttpResponse("时间{}的结果是:{}".format(ctime, result))
面试题七:对cookies与session的了解?他们能单独用吗?
session与cookies最核心区别在于额外信息由谁来维护。
- 利用cookies来实现会话管理时,用户的相关信息或者其他我们想要保持在每个请求中的信息,都是放在cookies中,而cookies是由客户端来保存,每当客户端发出新请求时,就会稍带上cookies,服务端会根据其中的信息进行操作。
- 当利用session来进行会话管理时,客户端实际上只存了一个由服务端发送的session_id,而由这个session_id,可以在服务端还原出所需要的所有状态信息,从这里可以看出这部分信息是由服务端来维护的。
因为Session是用Session ID来确定当前对话所对应的服务器Session,而Session ID是通过Cookie来传递的,禁用Cookie相当于SessionID,也就得不到Session。