WEB后端服务第17天-Django第7天
一、验证码
1.1 验证码方式
- 图片验证码
- 滑动验证码
- 短信验证码
- 邮箱验证码
1.2 验证码使用场景
- 防止爬虫程序
- 防止非人为操作
1.3 基于PIL库实现图片验证码
1.3.1 PIL初步使用
def new_img_code(request):
# 创建画布
img = Image.new('RGB', (80, 40), (100, 100, 0))
# 从画布中获取画笔
draw = ImageDraw.Draw(img, 'RGB')
# 创建字体对象和字体颜色
font_color = (0, 20, 100)
font = ImageFont.truetype(font='static/fonts/buding.ttf',
size=20)
# 开始画内容
draw.text((5, 5), '您好', font=font, fill=font_color)
for _ in range(100):
x = random.randint(0, 80)
y = random.randint(0, 40)
r = random.randint(0, 255)
g = random.randint(0, 255)
b = random.randint(0, 255)
draw.point((x, y), (r, g, b))
# 将画布写入内存字节数组中
from io import BytesIO
buffer = BytesIO()
img.save(buffer, 'png') # 写入
return HttpResponse(content=buffer.getvalue(),
content_type='image/png')
#!/usr/bin/python3
# coding: utf-8
import random
def _random_str(start, end):
return chr(random.randint(start, end))
def new_code_str(len):
code_str = ''
for _ in range(len):
flag = random.randint(0, 2)
start, end = (ord('a'), ord('z')) if flag == 1 \
else (ord('A'), ord('Z')) if flag == 2 \
else (ord('0'), ord('9'))
code_str += _random_str(start, end)
return code_str
if __name__ == '__main__':
print(new_code_str(6))
二、分页器Paginator
2.1 核心类
- django.core.paginator.Paginator
- Paginator(object_list, per_page) 创建分页器
- page(page_num) -> Page 获取page_num的分页对象
- page_range() -> generator 页号的范围
- django.core.paginator.Page
- page.object_list 当前页的数据集
- page.has_previous 是否有上一页
- page.previous_page_number 上一页页码
- page.has_next 是否有下一页
- page.next_page_number 下一页页码
- page.number 当前页的页码
2.2 分页器的应用
def order_list(request):
wd = request.GET.get('wd', '')
page = request.GET.get('page', 1)
orders = Order.objects.filter(Q(title__icontains=wd)).all()
# 分页器Paginator
paginator = Paginator(orders, 5)
pager = paginator.page(page) # 查询第page页
return render(request, 'list.html', locals())
<table border="1" cellspacing="0" cellpadding="2" width="100%">
<thead>
<th>ID</th>
<th>名称</th>
<th>单价</th>
<th>支付状态</th>
</thead>
<tbody>
{% for order in pager.object_list %}
<tr>
<td>{{ order.id }}</td>
<td>{{ order.title }}</td>
<td>{{ order.price }}</td>
<td>{{ order.pay_status_title }}</td>
</tr>
{% empty %}
<tr>
<td colspan="">查无此数据</td>
</tr>
{% endfor %}
</tbody>
</table>
<p style="text-align: center">
<a {% if pager.has_previous %} href="?page={{ pager.previous_page_number }}&wd={{ wd }}" {% endif %}><</a>
{% for p in paginator.page_range %}
{% if pager.number == p %}
<a class="page active"> {{ p }} </a>
{% else %}
<a class="page" href="?page={{ p }}&wd={{ wd }}"> {{ p }} </a>
{% endif %}
{% endfor %}
<a {% if pager.has_next %} href="?page={{ pager.next_page_number }}&wd={{ wd }}" {% endif %} >></a>
</p>
中午默写
1. response对象的content属性是什么
content是响应内容, 内容的数据类型可以字符串也可以字节码
如果响应内容是字节码时,需要指定content_type, 如 image/jpg, image/png
2. response.set_cookie()方法的参数有哪些
set_cookie(key, value, path='/', domain=None, max_age=None, expires=None)
3. 清除所有session的方法是什么
request.session.clear()
三、类视图 CBV
3.1 概念
Django中视图(View)写法有两种:
- FBV (Function-based View) 基于函数的视图, 之前都是使用FBV模式。
- CBV(Class-based View) 基于类的视图, 应用面向对象(OOB)设计思想, 通过继承、重写等相关特性实现业务功能。
3.2 Django提供很多的View
- View
- TemplateView
- RedirectView
- ListView
- EditView
- FormView
- DetailView
- DeleteView
3.3 使用的过程
-
在views.py中定义View的子类,并初始关键属性或重写方法
在View中处理的流程如下:
- dispatch(request, *args, **kwargs) 分发请求到get/post/put/delete/等方法处理函数中
- http_method_not_allowed() 请求方法不允许的响应
- options() 探测请求方法的Allow信息
-
在路由的视图函数位置上使用View.as_view()
from stockapp import views
app_name = 'stockapp'
urlpatterns = [
path('stocks/<stock_id>/',
csrf_exempt(views.StockView.as_view()),
name='stocks'),
path('goods/<wd>/', views.GoodsView.as_view(), name='goods'),
path('query/<wd>/', views.QueryView.as_view(), name='query')
]
class StockView(View):
def dispatch(self, request, *args, **kwargs):
return super().dispatch(request, *args, **kwargs)
def get(self, request, **kwargs):
# 获取请求路径中变量内容
stock_id = kwargs.get('stock_id')
return render(request, 'stock/list.html', locals())
def post(self, request):
return HttpResponse('Post请求')
四、中间件 Middleware
4.1 概念
中间件基于AOP(面向切面编程)设计思想, 目的扩展业务功能,即不修改原业务基础之上,增加新的功能,类似于装饰器。中间件有很多的使用场景: 验证权限、限制ip(黑名单)、限制请求次数、跨域请求、访问日志/统计、记录错误信息。
Django的中间件有五个勾子函数【重要】:
- process_request(request) 从django框架到urls路由过程
- process_view(request, callback, callback_args, callback_kwargs) 从urls路由到view视图函数的过程
- **process_template_response() ** 在view视图中渲染模板的过程【不常用】
- process_exception(request, exception) 从请求到响应的整过程,如果发生了异常,则会被此函数处理
- process_response(request, response) 从视图函数中向Django响应数据时, 即返回 HttpResponse()对象后
4.2 自定义中间件
中间件的基本类: django.utils.deprecation.MiddlewareMixin
在项目的目录下,创建middleware包和check_login.py脚本,内容如下:
from django.http import HttpResponse
from django.utils.deprecation import MiddlewareMixin
class CheckLoginMiddleware(MiddlewareMixin):
def process_request(self, request):
# 从请求到路由urls过程,触发此函数
dontfilters = ['/user/login/', '/user/code/']
if request.path not in dontfilters:
# 验证用户是否登录
if not request.COOKIES.get('token'):
return HttpResponse('<h3>Login</h3><form><input><button>Login</button></form>')
def process_view(self, request, callback, callback_args, callback_kwargs):
print('---CheckLoginMiddleware--', 'process_view')
# callback 是调用的view函数
# 新增一个关键参数, 类似于匹配路由 stock/<stock_id>/<page>/
# callback_kwargs['page'] = request.GET.get('page', 1)
print(callback, callback_args, callback_kwargs)
def process_response(self, request, response):
print('---CheckLoginMiddleware--', 'process_response')
return response # 必须返回响应对象
在settings.py的注册中间件类
MIDDLEWARE = [
'...'
'middleware.check_login.CheckLoginMiddleware',
]
五、Django日志
5.1 Django日志LOGGING的组成部分
- 日志的版本号 version
- 日志的格式化 formatters
- 日志的处理器 handlers
- 日志的记录器 loggers, 默认存在"django.server", “django.request”
- 日志的过滤器 filters
5.2 配置日志
在settings.py脚本中配置,内容如下:
# 配置Django的日志
LOGGING = {
'version': 1.0,
'formatters': {
'base': {
'format': '[%(asctime)s %(name)s ] %(message)s',
'datefmt': '%Y-%m-%d %H:%M:%S'
}
},
'handlers': {
'out': {
'class': 'logging.StreamHandler',
'level': 'INFO',
'formatter': 'base'
},
'file': {
'class': 'logging.FileHandler',
'level': 'WARNING',
'formatter': 'base',
'filename': f'{BASE_DIR}/warn.log'
}
},
'loggers': {
# 日志记录器 django.server
'django.server': {
'handlers': ['out', 'file'],
'level': 'CRITICAL',
'propagate': False
},
'mylogger': {
'handlers': ['out', 'file'],
'level': 'INFO',
'propagate': False
}
}
}
5.3 使用日志
import logging
logging.getLogger('mylogger').error('请求发生错误')
5.4 扩展: Django默认日志配置源码
源码脚本: django.utils.log.py
DEFAULT_LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'require_debug_false': {
'()': 'django.utils.log.RequireDebugFalse',
},
'require_debug_true': {
'()': 'django.utils.log.RequireDebugTrue',
},
},
'formatters': {
'django.server': {
'()': 'django.utils.log.ServerFormatter',
'format': '[%(server_time)s] %(message)s',
}
},
'handlers': {
'console': {
'level': 'INFO',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
},
'django.server': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'django.server',
},
'mail_admins': {
'level': 'ERROR',
'filters': ['require_debug_false'],
'class': 'django.utils.log.AdminEmailHandler'
}
},
'loggers': {
'django': {
'handlers': ['console', 'mail_admins'],
'level': 'INFO',
},
'django.server': {
'handlers': ['django.server'],
'level': 'INFO',
'propagate': False,
},
}
}
六、缓存Cache
6. 1 配置缓存
6.1.1 文件缓存
# 配置缓存Cache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': f'{BASE_DIR}/mycache',
'TIMEOUT': 300,
'OPTIONS': {
'MAX_ENTRIES': 500,
'CULL_FREQUENCY': 3
}
}
}
6.2 使用缓存
6.2.1 文件缓存的使用
导包
from django.core.cache import cahce
增加
cache.set(key, value, timeout)
cache.add(key, value,timeout, version)
读取
cache.has_key(key)
value = cache.get(key)
删除
cache.delete(key)