Django之使用celery和NGINX生成静态页面实现性能优化


Posted in Python onOctober 08, 2019

性能优化原理:

当我们要给client浏览器返回一个页面时,我们需要去数据库查询数据并将数据和基本页面模板渲染形成页面返回给客户端,但如果每一个用户访问时都去查询一次首页的的数据时,当日访问量很大时那么无疑会给数据库查询带来很大的性能问题。为了解决这个问题,我们可以给未登录用户返回一个早就渲染好的静态首页(给已登录的用户返回一个调用缓存数据和个人数据渲染的页面),这样就可以提高网站的性能了。

使用celery生成静态首页

生成静态页面原理:

在一个为静态首页准备的基础模板之上,获取数据,使用django的loader加载基础模板,使用render渲染页面即可生成几台页面。

安装celery

pip install celery

为redis配置settings文件

# diango的缓存配置
CACHES = {
 "default": {
  "BACKEND": "django_redis.cache.RedisCache",
  "LOCATION": "redis://127.0.0.1:6379/9",
  "OPTIONS": {
   "CLIENT_CLASS": "django_redis.client.DefaultClient",
  }
 }
}

准备一个首页静态模板文件static_base.html

{# 首页 注册 登录 #}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
{% load staticfiles %}
<head>
 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
 {# 网页标题内容块 #}
 <title>{% block title %}{% endblock title %}</title>
 <link rel="stylesheet" type="text/css" href="{% static 'css/reset.css' %}">
 <link rel="stylesheet" type="text/css" href="{% static 'css/main.css' %}">
 {# 网页顶部引入文件块 #}
 {% block topfiles %}{% endblock topfiles %}
</head>
<body>
{# 网页顶部欢迎信息块 #}
{% block header_con %}
 <div class="header_con">
  <div class="header">
   <div class="welcome fl">欢迎来到商城!</div>
   <div class="fr">
    <div class="login_btn fl">
     <a href="{% url 'user:login' %}">登录</a>
     <span>|</span>
     <a href="{% url 'user:register' %}">注册</a>
    </div>
    <div class="user_link fl">
     <span>|</span>
     <a href="{% url 'user:user' %}">用户中心</a>
     <span>|</span>
     <a href="cart.html">我的购物车</a>
     <span>|</span>
     <a href="{% url 'user:order' %}">我的订单</a>
    </div>
   </div>
  </div>  
 </div>
{% endblock header_con %}

{# 网页顶部搜索框块 #}
{% block search_bar %}
 <div class="search_bar clearfix">
  <a href="index.html" class="logo fl"><img src="{% static 'images/logo.png' %}"></a>
  <div class="search_con fl">
   <input type="text" class="input_text fl" name="" placeholder="搜索商品">
   <input type="button" class="input_btn fr" name="" value="搜索">
  </div>
  <div class="guest_cart fr">
   <a href="#" class="cart_name fl">我的购物车</a>
   <div class="goods_count fl" id="show_count">{{ cart_count }}</div>
  </div>
 </div>
{% endblock search_bar %}

{# 网站主体内容块 #}
{% block body %}{% endblock body %}

 <div class="footer">
  <div class="foot_link">
   <a href="#">关于我们</a>
   <span>|</span>
   <a href="#">联系我们</a>
   <span>|</span>
   <a href="#">招聘人才</a>
   <span>|</span>
   <a href="#">友情链接</a>  
  </div>
  <p>CopyRight © 2016 北京商城信息技术有限公司 All Rights Reserved</p>
  <p>电话:010-****888 京ICP备*******8号</p>
 </div>
 {# 网页底部html元素块 #}
 {% block bottom %}{% endblock bottom %}
 {# 网页底部引入文件块 #}
 {% block bottomfiles %}{% endblock bottomfiles %}
</body>
</html>

在首页静态模板文件的基础上继承生成一个首页静态文件 static_index.html 方便celery获取数据库文件并进行渲染

{% extends 'static_base.html' %}
{% load staticfiles %}
{% block title %}首页{% endblock title %}
{% block topfiles %}
 <script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js' %}"></script>
 <script type="text/javascript" src="{% static 'js/jquery-ui.min.js' %}"></script>
 <script type="text/javascript" src="{% static 'js/slide.js' %}"></script>
{% endblock topfiles %}
{% block body %}
 <div class="navbar_con">
  <div class="navbar">
   <h1 class="fl">全部商品分类</h1>
   <ul class="navlist fl">
    <li><a href="">首页</a></li>
    <li class="interval">|</li>
    <li><a href="">手机生鲜</a></li>
    <li class="interval">|</li>
    <li><a href="">抽奖</a></li>
   </ul>
  </div>
 </div>

 <div class="center_con clearfix">
  <ul class="subnav fl">
   {% for type in types %}
    <li><a href="#model0{{ forloop.counter }}" class="{{ type.logo }}">{{ type.name }}</a></li>
   {% endfor %}
  </ul>
  <div class="slide fl">
   <ul class="slide_pics">
    {% for banner in goods_banners %}
     <li><a href="#"><img src="{{ banner.image.url }}" alt="幻灯片"></a></li>
    {% endfor %}
   </ul>
   <div class="prev"></div>
   <div class="next"></div>
   <ul class="points"></ul>
  </div>
  <div class="adv fl">
   {% for banner in promotion_banners %}
    <a href="{{ banner.url }}"><img src="{{ banner.image.url }}"></a>
   {% endfor %}
  </div>
 </div>

 {% for type in types %}
 <div class="list_model">
  <div class="list_title clearfix">
   <h3 class="fl" id="model0{{ forloop.counter }}">{{ type.name }}</h3>
   <div class="subtitle fl">
    <span>|</span>
    {% for banner in type.title_banners %}
     <a href="#">{{ banner.sku.name }}</a>
    {% endfor %}
   </div>
   <a href="#" class="goods_more fr" id="fruit_more">查看更多 ></a>
  </div>

  <div class="goods_con clearfix">
   <div class="goods_banner fl"><img src="{{ type.image.url }}"></div>
   <ul class="goods_list fl">
    {% for banner in type.image_banners %}
    <li>
     <h4><a href="#">{{ banner.sku.name }}</a></h4>
     <a href="#"><img src="{{ banner.sku.image.url }}"></a>
     <div class="prize">¥ {{ banner.sku.price }}</div>
    </li>
    {% endfor %}
   </ul>
  </div>
 </div>
 {% endfor %}
{% endblock body %}

在项目下新建celery_tasks文件夹,在文件夹中新建tasks.py文件, 编写tasks文件

from django.conf import settings
from celery import Celery
from django.template import loader

# 在任务处理者一端加这几句
import os
# import django
# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shoppingmall.settings")
# django.setup()

# 这几个类要放在django环境初始化那四句的下面
from goods.models import GoodsType, IndexGoodsBanner, IndexPromotionBanner, IndexTypeGoodsBanner

# 创建一个Celery类的实例对象
app = Celery('celery_tasks.tasks', broker='redis://127.0.0.1:6379/8')


@app.task
def generate_static_index_html():
 '''产生首页静态页面'''
 # 获取商品的种类信息
 types = GoodsType.objects.all()
 # 获取首页轮播商品信息
 goods_banners = IndexGoodsBanner.objects.all().order_by('index')
 # 获取首页促销活动信息
 promotion_banners = IndexPromotionBanner.objects.all().order_by('index')
 # 获取首页分类商品展示信息
 for type in types: # GoodsType
  # 获取type种类首页分类商品的图片展示信息
  image_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=1).order_by('index')
  # 获取type种类首页分类商品的文字展示信息
  title_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=0).order_by('index')
  # 动态给type增加属性,分别保存首页分类商品的图片展示信息和文字展示信息
  type.image_banners = image_banners
  type.title_banners = title_banners

 # 组织模板上下文
 context = {
    'types': types,
    'goods_banners': goods_banners,
    'promotion_banners': promotion_banners
   }

 # 使用模板
 # 1.加载模板文件,返回模板对象
 temp = loader.get_template('static_index.html')
 # 2.模板渲染
 static_index_html = temp.render(context)

 # 生成首页对应静态文件
 save_path = os.path.join(settings.BASE_DIR, 'static/index.html')
 with open(save_path, 'w', encoding='utf-8') as f:
  f.write(static_index_html)

开启redis服务

E:\>cd E:\YifChanSoft\Database\Redis\RedisSoft\Redis-x64-3.2.100

E:\YifChanSoft\Database\Redis\RedisSoft\Redis-x64-3.2.100>redis-server --service-install redis.windows-service.conf --loglevel verbose

E:\YifChanSoft\Database\Redis\RedisSoft\Redis-x64-3.2.100>redis-cli
127.0.0.1:6379> select 8
OK
127.0.0.1:6379[8]> keys *
1) "_kombu.binding.celery"
2) "_kombu.binding.celery.pidbox"
127.0.0.1:6379[8]>

开启redis服务截图

Django之使用celery和NGINX生成静态页面实现性能优化

将项目代码拷贝一份放在某处,进入该处, 启动tasks的worker模式

注意,用作worker的代码的tasks文件中应该有提前启动django的初始化的代码,不然worker没法调用conf信息;

即应该有以下内容

# 在任务处理者一端加这几句
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shoppingmall.settings")
django.setup()

为了解决celery4.x在win10上运行的错误,安装eventlet

pip install eventlet

进入复制用来做celery工作者的项目代码所在处

开启worker模式

celery -A celery_tasks.tasks worker -l info -P eventlet

开启worker模式截图

Django之使用celery和NGINX生成静态页面实现性能优化

如果有就删除celery代码文件中static中的index.html文件;

主动调用 generate_static_index_html.delay() 即可验证生成index.html;

from celery_tasks.tasks import generate_static_index_html
generate_static_index_html.delay()

验证截图

Django之使用celery和NGINX生成静态页面实现性能优化

可以看到在项目下的static文件夹下生成了index.html;

开启项目在浏览器中输入 http://127.0.0.1:8888/static/index.html/ 即可看到生成的静态首页;因为数据库中还没有数据,所以页面比较空。

Django之使用celery和NGINX生成静态页面实现性能优化

NGINX的安装

参考教程: https://3water.com/article/171374.htm

1.下载nginx: http://nginx.org/en/download.html

Django之使用celery和NGINX生成静态页面实现性能优化

2.解压缩nginx包

下载好后在放入合适的目录,解压缩后如下

Django之使用celery和NGINX生成静态页面实现性能优化

3.使用cmd命令,进入nginx所在解压缩目录,使用如下命令进行 安装nginx

start nginx.exe

安装截图

Django之使用celery和NGINX生成静态页面实现性能优化

安装完成后,我们可以在 任务管理器中看到nginx任务,如图

Django之使用celery和NGINX生成静态页面实现性能优化

至此,nginx就算安装完成了。

nginx命令

start nginx.exe # 开启nginx
nginx -s reload # 重新启动
nginx -s stop # 停止nginx
nginx -s quit # 退出nginx

使用NGINX提供静态首页

修改nginx配置

找到nginx的配置文件,如下图所示,为了方便以后其他的项目使用,我们拷贝一份源文件重命名为nginx_origin.conf

Django之使用celery和NGINX生成静态页面实现性能优化

用编辑器打开 nginx.conf 文件,修改配置文件中内容如下:

location /static {
 alias E:/Pycharm/Pycharm_save/cp15/18Django_fresh2/step206/shoppingmall206/static/;
}

location / {
 # root html;
 root E:/Pycharm/Pycharm_save/cp15/18Django_fresh2/step206/shoppingmall206/static/;
 index index.html index.htm;
}

配置截图

Django之使用celery和NGINX生成静态页面实现性能优化

注意,其中的地址应该是你使用celery的项目所在的绝对路径地址,并且地址之间应该使用斜杠/而不是反斜杠\,否则会报错。

修改好配置保存后,我们使用一下命令进行nginx的重启

nginx -s reload

然后,我们打开浏览器输入一下两个链接之一就可以看到项目主页面了。

http://127.0.0.1/ # 注意,后面必须有一个/,否则会进入nginx默认界面
http://127.0.0.1/static/index.html

项目主页面截图

Django之使用celery和NGINX生成静态页面实现性能优化

nginx的cmd命令截图,其中的报错都是因为使用的是win10目录自带的反斜杠

Django之使用celery和NGINX生成静态页面实现性能优化

在Django网站和celery可以理解是并列的关系,在他们之前,其实还有一个nginx服务器负责调度;

一般是当用户直接访问127.0.0.1时,我们通过nginx调度去celery的nginx中返回静态页面;

而当用户访问127.0.0.1/index时,我们返回调用Django网站的IndexView;

在网站上线时我们会使用nginx对它们进行配置。

后台数据修改时重新生成静态页面

原理

在数据库的数据改变时,会调用admin.ModelAdmin下的sava_model和delete_model方法用来更新数据,而我们需要当数据改变后重新生成静态页面;

因此,我们可以自定义一个类继承admin.ModelAdmin,重写更新和删除数据的方法,调用父类的更新删除方法后,调用celery中的方法重新生成静态首页;

实现

我们要配置当某个表的数据改变时重新生成静态页面,就要给该表定义一个 xxxModelAdmin 类,继承自admin.ModelAdmin并重写其中的方法,并且在admin中注册时该表应该同时继承xxxModelAdmin 类;

因为有很多表都需要如此配置,且类中的代码都相同,所以我们可以抽出一个 BaseModelAdmin 类,编写更新后重新调用生成静态页面的代码,然后让各个需要修改的表继承该类即可。

在首页对应的应用中的admin.py文件中编写如下代码

from django.contrib import admin
# from django.core.cache import cache
from goods.models import GoodsType, GoodsSKU, Goods, GoodsImage, IndexGoodsBanner, IndexTypeGoodsBanner, IndexPromotionBanner
from celery_tasks.tasks import generate_static_index_html


class BaseModelAdmin(admin.ModelAdmin):
 """当后台数据库数据改动时使celery重新生成静态首页页面"""
 def save_model(self, request, obj, form, change):
  """当更新或者新增数据时调用"""
  super().save_model(request, obj, form, change)
  # 发出任务,让celery worker重新生成静态首页
  generate_static_index_html.delay()

  # 清除首页的缓存数据
  # cache.delete("index_page_data")

 def delete_model(self, request, obj):
  """当删除数据时调用"""
  super().delete_model(request, obj)
  generate_static_index_html.delay()

  # 清除首页的缓存数据
  # cache.delete("index_page_data")


class GoodsTypeAdmin(BaseModelAdmin):
 pass


class IndexGoodsBannerAdmin(BaseModelAdmin):
 pass


class IndexTypeGoodsBannerAdmin(BaseModelAdmin):
 pass


class IndexPromotionBannerAdmin(BaseModelAdmin):
 pass


admin.site.register(GoodsType, GoodsTypeAdmin)
admin.site.register(GoodsSKU)
admin.site.register(Goods)
admin.site.register(GoodsImage)
admin.site.register(IndexGoodsBanner, IndexGoodsBannerAdmin)
admin.site.register(IndexTypeGoodsBanner, IndexTypeGoodsBannerAdmin)
admin.site.register(IndexPromotionBanner, IndexPromotionBannerAdmin)

至此,当我们在admin后台更新数据时就会重新生成静态首页了,大家可以自行尝试一下~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
ssh批量登录并执行命令的python实现代码
May 25 Python
在Python的web框架中中编写日志列表的教程
Apr 30 Python
Python实现在matplotlib中两个坐标轴之间画一条直线光标的方法
May 20 Python
python计算文本文件行数的方法
Jul 06 Python
Python第三方库的安装方法总结
Jun 06 Python
python实现手机通讯录搜索功能
Feb 22 Python
OPENCV去除小连通区域,去除孔洞的实例讲解
Jun 21 Python
对Python生成器、装饰器、递归的使用详解
Jul 19 Python
Python实现变声器功能(萝莉音御姐音)
Dec 05 Python
Python如何使用paramiko模块连接linux
Mar 18 Python
Pycharm中配置远程Docker运行环境的教程图解
Jun 11 Python
Python机器学习之KNN近邻算法
May 14 Python
Django中使用haystack+whoosh实现搜索功能
Oct 08 #Python
python 使用while写猜年龄小游戏过程解析
Oct 07 #Python
python getpass模块用法及实例详解
Oct 07 #Python
Python拆分大型CSV文件代码实例
Oct 07 #Python
Python模块汇总(常用第三方库)
Oct 07 #Python
python numpy之np.random的随机数函数使用介绍
Oct 06 #Python
python系列 文件操作的代码
Oct 06 #Python
You might like
php之对抗Web扫描器的脚本技巧
2008/10/01 PHP
PHP Google的translate API代码
2008/12/10 PHP
php获取客户端IP及URL的方法示例
2017/02/03 PHP
php高清晰度无损图片压缩功能的实现代码
2018/12/09 PHP
javascript cookies 设置、读取、删除实例代码
2010/04/12 Javascript
jQuery学习笔记之Helloworld
2010/12/22 Javascript
javascript之Partial Application学习
2013/01/10 Javascript
jquery修改属性值实例代码(设置属性值)
2014/01/06 Javascript
jQuery循环动画与获取组件尺寸的方法
2015/02/02 Javascript
javaScript基础语法介绍
2015/02/28 Javascript
一分钟理解js闭包
2016/05/04 Javascript
Three.js学习之正交投影照相机
2016/08/01 Javascript
最丑的时钟效果!js canvas时钟制作方法
2016/08/15 Javascript
jQuery表单验证简单示例
2016/10/17 Javascript
jQuery延迟执行的实现方法
2016/12/21 Javascript
详谈Node.js之操作文件系统
2017/08/29 Javascript
浅谈vue中使用图片懒加载vue-lazyload插件详细指南
2017/10/23 Javascript
小程序input数据双向绑定实现方法
2019/10/17 Javascript
vue-cli3项目升级到vue-cli4 的方法总结
2020/03/19 Javascript
解决vscode进行vue格式化,会自动补分号和双引号的问题
2020/10/26 Javascript
400多行Python代码实现了一个FTP服务器
2012/05/10 Python
python使用matplotlib绘制柱状图教程
2017/02/08 Python
Tensorflow之构建自己的图片数据集TFrecords的方法
2018/02/07 Python
Python爬虫工程师面试问题总结
2018/03/22 Python
python异步存储数据详解
2019/03/19 Python
对pyqt5多线程正确的开启姿势详解
2019/06/14 Python
瑞贝卡·泰勒官方网站:Rebecca Taylor
2016/09/24 全球购物
JD Sports澳洲官网:英国领先的运动鞋和运动时尚零售商
2020/02/15 全球购物
C语言变量的命名规则都有哪些
2013/12/27 面试题
武汉某公司的C#笔试题面试题
2015/12/25 面试题
消防战士优秀事迹材料
2014/02/13 职场文书
食品流通安全承诺书
2014/05/22 职场文书
思想作风整顿个人剖析材料
2014/10/06 职场文书
担保书格式范文
2015/09/22 职场文书
Python 阶乘详解
2021/10/05 Python
浅谈克隆 JavaScript
2021/11/02 Javascript