1、自定义过滤器
Django提供了很多过滤器,但有时并不能满足我们的需求,这时候就需要自定义过滤器来实现某种功能。
1.1 步骤
1、创建templatetags包
名字是固定的,不能随意改动
2、 在templatetags包里创建文件,用来存放过滤器函数,文件名字可以任意。
3、编写过滤器函数
from django.template import Library
register = Library() # 实例化模板库
@register.filter # 用来注册过过滤器的装饰器
def phone_filter(phone):
"""接收并返回过滤的结果函数"""
result = phone[:3]+"***"+phone[-4:] # 对号码进行处理
return result # 返回过滤结果
4、使用过滤器
{% load buyer_filter %} <!-- 加载过滤器 -->
<p class="text-center">{% phone|phone_filter %}</p> <!-- 使用phone_filter过滤器 -->
2、自定义实体类管理器
通常我们通过模型的objects方法调用查询的方法,实质上,objects是Django模型动态生成的一个查询类,这个查询类继承了models.Manager。
2.1 步骤
1、定义类
from django.db.models import Manager
class SellerManager(Manager):
"""自定义管理器类"""
def get_name(self, id):
"""根据id查询并返回结果名字"""
return Seller.objects.get(pk=id).name
2、将定义的类复制到objects
class Seller(models.Model):
"""seller卖家"""
name = models.CharField(max_length=64)
password = models.CharField(max_length=64)
nickname = models.CharField(max_length=64, null=True)
...
objects = SellerManager() # 自定义manager管理器对象,名字是objects
1个实体类只有能有1个名字是objects的管理器,如果定义其他管理器了,objects就没有。
3、测试
3、中间件
中间件是处理Django请求和响应的框架级别的钩子,它是一个轻量、低级别的插件系统,用于全局范围内改变Django的输入和输出,每一个中间件都有固定的功能,使用需要很谨慎。中间件尽可能的解决了项目代码冗余和代码一致性问题。简单的讲django中间件是django提供给用户可以影响全局请求和响应的接口。
3.1 中间件方法及使用
中间件在使用前需要settings中设置
中间件有五个方法,下图为各个中间件的执行顺序:
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class MyMiddleware(MiddlewareMixin):
"""中间件"""
def process_request(self, request):
"""
请求开始,在视图函数之前执行的。
:param request: 包含请求信息的请求对象
:return:
"""
print("process_request")
def process_view(self, request, callback, callbackarg, callbackkwargs):
"""
视图函数之前,process_request 方法之后执行的
:param request:包含请求信息的请求对象,但有可能被process_request处理
:param callback:处理请求的函数
:param callbackarg:元组参数
:param callbackkwargs:字典参数
参数:通过路由中的正则匹配到内容
元组参数:正则中使用组匹配
字典参数:正则中使用组匹配 + 别名
:return:
"""
print("process_views")
def process_exception(self, request, exception):
"""错误"""
print("process_exception")
def process_template_response(self, request, response):
"""视图结束,模板开始渲染"""
print("process_template_response")
return response
def process_response(self, request, response):
"""响应结束"""
print("process_response")
return response
3.1.1 process_request (常用)
请求开始,在视图函数之前执行的。可以用来禁止被封的ip访问
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class MyMiddleware(MiddlewareMixin):
"""自定义中间件"""
def process_request(self, request):
"""
:param request: 包含请求信息的请求对象
:return:
"""
print("process_request")
ips = ["127.0.0.1"]
# 获取IP
ip = request.META.get("REMOTE_ADDR")
# 判断
if ip in ips:
# 响应,真实环境可以选择渲染到一个页面
return HttpResponse("你已经被禁止了...")
3.1.2 process_views
视图函数之前,process_request 方法之后执行的,也可以理解为视图预处理
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class MyMiddleware(MiddlewareMixin):
"""自定义中间件"""
def process_view(self, request, callback, callbackarg, callbackkwargs):
"""
:param request:包含请求信息的请求对象,但有可能被process_request处理
:param callback:处理请求的函数
:param callbackarg:元组参数
:param callbackkwargs:字典参数
参数:通过路由中的正则匹配到内容
元组参数:正则中使用组匹配
字典参数:正则中使用组匹配 + 别名
:return:
"""
print("process_views")
print(callback)
print(callbackarg)
print(callbackkwargs)
if int(callbackkwargs.get("version").split("v")[-1]) <= 1:
return HttpResponse("版本太低")
3.1.3 process_exception
视图发生错误时执行的函数,一般可以用来记录日志
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class MyMiddleware(MiddlewareMixin):
"""自定义中间件"""
def process_exception(self, request, exception):
print("process_exception")
print(exception)
import os
import time
now_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
from shop.settings import BASE_DIR
file = os.path.join(BASE_DIR, "error.log")
content = f"[{now_time}]:{str(exception)}"
with open(file, 'w', encoding='utf-8') as fp:
fp.write(content)
return HttpResponse("错误")
3.1.4 process_template_response
视图结束,模板开始渲染。默认不会执行,它对视图函数格式是有要求的:视图函数的返回响应对象必须有render方法。
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class MyMiddleware(MiddlewareMixin):
"""自定义中间件"""
def process_template_response(self, request, response):
print("process_template_response")
return response
from django.template import loader
def skip(request):
print("测试路由")
# 创建响应对象
response = HttpResponse()
# 准备数据字典
con = {"name": "laowang"}
# 内部render方法
def myrender():
print("skip内的myrender方法")
# 加载模板
template = loader.get_template("store/skip.html")
# 设置响应内容,template.render(con)将变量渲染到模板中,得到渲染后的html
response.content = template.render(con)
# 返回响应对象
return response
# 给响应对象设置render
response.render = myrender
return response
<!--skip.html-->
<p>{{ name }}</p>
3.1.5 process_response(常用)
响应结束,可以对所有的返回结果做处理,例如:设置响应头,设置返回的数据类型,设置cookie、session,同一返回的格式。
from django.utils.deprecation import MiddlewareMixin
class MyMiddleware(MiddlewareMixin):
"""自定义中间件"""
def process_response(self, request, response):
print("process_response")
response.set_cookie("test", "process_response")
return response
4、缓存
Django用来做动态网站,每次请求页面都需要进行各种运算,然后从数据库当中取得数据,染好呈现到业务逻辑。从处理开销的角度来看,这个成本比在文本里读取内容大很多。这个时候,对常用的数据存放到独立的一个容器当中,当用户请求,不再直接数据库去取数据,而是先从容器里找。这种技术叫做缓存技术。这个容器可以是内存,文件,数据库或者专业缓存服务器(Memcache)。
缓存的优点:
提高访问速度,降低服务器的压力(主要是数据库相关)。
使用场景:
经常做查询,不要求实时数据,数据量大并且业务复杂,例如电商的首页,上月的话费信息等等
内存缓存是缓存手段当中最快的,但是有内存溢出漏洞。
文件缓存是缓存当中性价比最高,但是有安全漏洞。
数据库缓存,再创建一个表存放经常查询的数据,设计难度比较高。
Django默认没有设置缓存,需要自己设置,可以在全局配置中找缓存配置
4.1 内存缓存
配置信息
# 缓存到内存
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', # 缓存后台使用的引擎
'LOCATION': 'my_cache', # 缓存名称
'TIMEOUT': 300, # 缓存超时时间(默认300秒,None表示永不过期,0表示立即过期)
'OPTIONS': {
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
}
}
4.2 文件缓存
# 缓存到文件
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', # 缓存后台使用的引擎
'LOCATION': os.path.join(BASE_DIR, "file_cache"), # 缓存到本地的文件夹
'TIMEOUT': 300, # 缓存超时时间(默认300秒,None表示永不过期,0表示立即过期)
'OPTIONS': {
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
}
}
4.3 数据库缓存
需要创建数据库,在命令行中输入下面命令创建数据库
python manage.py createcachetable
# 此缓存将内容保存至数据库中
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache', # 缓存后台使用的引擎
'LOCATION': 'table_cache', # 数据库表,表名自动生成
'TIMEOUT': 300, # 缓存超时时间(默认300秒,None表示永不过期,0表示立即过期)
'OPTIONS': {
'MAX_ENTRIES': 300, # 最大缓存记录的数量(默认300)
'CULL_FREQUENCY': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
}
}
4.4 memcache缓存
4.4.1 安装memcache服务器
下载解压后以管理员的身份进入命令窗口,切换到解压后的文件夹下执行下面的命令,安装memcache
memcached.exe -d install
4.4.2 安装python memcached模块
pip install python-memcached
4.4.3 配置
# 此缓存将内容保存至Memcached中
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', # 缓存后台使用的引擎
'LOCATION': '127.0.0.1:11211', # Memcached地址
'TIMEOUT': 300, # 缓存超时时间(默认300秒,None表示永不过期,0表示立即过期)
}
}
4.5 缓存的使用
缓存技术是提高访问效率,降低服务器压力的一种网站调优手段。一般我们都是使用memcache缓存。
4.5.1 缓存原理图解:
4.5.2 视图中使用
from django.views.decorators.cache import cache_page
@cache_page(10)
def test_cache(request):
print("*" * 100)
now = datetime.now().strftime("%H:%M:%S")
return HttpResponse(now)
4.5.3 路由中使用
from django.urls import path
from django.views.decorators.cache import cache_page
from store.views import test_cache
urlpatterns = [
path("test_cache/", cache_page(10)(test_cache)), # 单位是秒
]
4.5.4 html中使用
def test_cache(request):
print("*" * 100)
now = datetime.now().strftime("%H:%M:%S")
return render(request, "store/test_cache.html", locals())
<!--test_cache.html-->
{% load cache %}
<p>现在时间{{ now }}</p>
<hr>
{% cache 10 test_cache %} {# 单位是秒,名字随意起 #}
<p>缓存时间{{ now }}</p>
{% endcache %}
4.5.5 全局使用
全局使用反而给memcache服务增添了压力,一般不采用这种方法
4.5.6 底层cache使用(推荐使用)
1、导包
from django.core.cache import cache
2、方法
get 获取缓存 cache.get(key)
set 设置缓存 cache.set(key,value,timeout)
delete 删除缓存 cache.delete(key)
3、流程
请求数据,判断缓存中是否存在数据,如果有,直接返回数据,如果没有,从数据中查询,设置缓存返回结果。一般缓存的数据更新的话也要重新设置,避免无效或错误信息一直给用户显示。
4、案例:缓存首页的商品数据
from django.core.cache import cache
from store.models import GoodsType
def set_cache():
"""查询并设置缓存"""
goods_type = GoodsType.objects.all()
cache.set("goods_type_cache", goods_type, 60 * 60 * 24)
print("*" * 100)
@login_check(url)
def index(request):
goods_type = cache.get("goods_type_cache")
if not goods_type:
# 查询并设置缓存
set_cache()
return render(request, "buyer/index.html", locals())
新增商品时重新设置缓存
@login_check(url)
def goods(request):
if request.method == "POST":
# 获取post提交的数据
name = request.POST.get("name")
price = request.POST.get("price")
number = request.POST.get("number")
goods = Goods()
goods.name = name
goods.price = price
goods.number = number
goods.save()
# 更新成功后重新设置缓存
from buyer.views import set_cache
set_cache()
return redirect("/store/goods/")
return render(request, "store/goods.html", locals())