在工作中接盘,遇到商城的首页被频繁访问(频繁查询数据库)导致宕机,但首页数据变动频率较低,如果通过静态html展示那么在访问速度会有很大的提升,并且对seo有很大帮助.
理解
页面静态化即将动态渲染生成的页面结果保存成html文件,放到静态文件服务器中。用户访问的时候访问的直接是处理好之后的html静态文件
对于页面中属于每个用户展示不同数据内容的部分,可以在用户请求完静态化之后的页面后,在页面中向后端发送请求,获取属于用户的特殊的数据
用到的库
django-crontab
- 1
大体流程
准备页面静态化(模板渲染脚本)
V
配置渲染的静态页面存储位置
V
确认需要静态化的模板,进行Vue模板语法的处理
V
准备静态化脚本
V
设置定时任务
V
启动
代码(Django框架下)
新建crons.py 存储页面静态化逻辑
import time
import os
from goods.models import GoodsChannel
from .models import ContentCategory
from collections import OrderedDict
from django.template import loader
from django.conf import settings
def generate_static_index_html():
"""
生成静态的主页html
"""
print('%s:generate_static_index' % time.ctime())
# 商品频道及分类菜单
# 使用有序字典保存类别的顺序
# categories = {
# 1: { # 组1
# 'channels': [{'id':, 'name':, 'url':},{}, {}...],
# 'sub_cats': [{'id':, 'name':, 'sub_cats':[{},{}]}, {}, {}, ..]
# },
# 2: { # 组2
#
# }
# }
# 初始化存储容器
categories = OrderedDict()
# 获取一级分类
channels = GoodsChannel.objects.order_by('group_id', 'sequence')
# 对一级分类进行遍历
for channel in channels:
# 获取group_id
group_id = channel.group_id
# 判断group_id 是否在存储容器,如果不在就初始化
if group_id not in categories:
categories[group_id] = {
'channels': [],
'sub_cats': []
}
one = channel.category
# 为channels填充数据
categories[group_id]['channels'].append({
'id': one.id,
'name': one.name,
'url': channel.url
})
# 为sub_cats填充数据
for two in one.goodscategory_set.all():
# 初始化 容器
two.sub_cats = []
# 遍历获取
for three in two.goodscategory_set.all():
two.sub_cats.append(three)
# 组织数据
categories[group_id]['sub_cats'].append(two)
# 广告和首页数据
contents = {}
content_categories = ContentCategory.objects.all()
# content_categories = [{'name':xx , 'key': 'index_new'}, {}, {}]
# {
# 'index_new': [] ,
# 'index_lbt': []
# }
for cat in content_categories:
contents[cat.key] = cat.content_set.filter(status=True).order_by('sequence')
context = {
'categories': categories,
'contents': contents
}
template = loader.get_template('index.html')
html_data = template.render(context)
#将文件写入
file_path = os.path.join(settings.GENERATED_STATIC_HTML_FILES_DIR,'index.html')
with open(file_path,'w') as f:
f.write(html_data)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
配置settings
# 生成的静态html文件保存目录
GENERATED_STATIC_HTML_FILES_DIR = os.path.join(os.path.dirname(BASE_DIR), 'front')
- 1
- 2
在工程目录中新建templates模板目录
在模板目录中新建index.html模板文件,copy模板代码
<!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">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>******商城-首页</title>
<link rel="stylesheet" type="text/css" href="css/reset.css">
<link rel="stylesheet" type="text/css" href="css/main.css">
<script type="text/javascript" src="js/host.js"></script>
<script type="text/javascript" src="js/vue-2.5.16.js"></script>
<script type="text/javascript" src="js/axios-0.18.0.min.js"></script>
<script type="text/javascript" src="js/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="js/slide.js"></script>
</head>
<body>
<div id="app" v-cloak>
<div class="header_con">
<div class="header">
<div class="welcome fl">欢迎来到*****商城!</div>
<div class="fr">
<div v-if="username" class="login_btn fl">
欢迎您:<em>[[ username ]]</em>
<span>|</span>
<a @click="logout">退出</a>
</div>
<div v-else class="login_btn fl">
<a href="login.html">登录</a>
<span>|</span>
<a href="register.html">注册</a>
</div>
<div class="user_link fl">
<span>|</span>
<a href="user_center_info.html">用户中心</a>
<span>|</span>
<a href="cart.html">我的购物车</a>
<span>|</span>
<a href="user_center_order.html">我的订单</a>
</div>
</div>
</div>
</div>
<div class="search_bar clearfix">
<a href="index.html" class="logo fl"><img src="images/logo.png"></a>
<div class="search_wrap fl">
<form method="get" action="/search.html" class="search_con">
<input type="text" class="input_text fl" name="q" placeholder="搜索商品">
<input type="submit" class="input_btn fr" name="" value="搜索">
</form>
<ul class="search_suggest fl">
<li><a href="#">索尼微单</a></li>
<li><a href="#">优惠15元</a></li>
<li><a href="#">美妆个护</a></li>
<li><a href="#">买2免1</a></li>
</ul>
</div>
<div class="guest_cart fr">
<a href="#" class="cart_name fl">我的购物车</a>
<div class="goods_count fl" id="show_count">15</div>
<ul class="cart_goods_show">
<li>
<img src="images/goods/goods001.jpg" alt="商品图片">
<h4>商品名称手机</h4>
<div>4</div>
</li>
<li>
<img src="images/goods/goods002.jpg" alt="商品图片">
<h4>商品名称手机</h4>
<div>5</div>
</li>
<li>
<img src="images/goods/goods003.jpg" alt="商品图片">
<h4>商品名称手机</h4>
<div>6</div>
</li>
<li>
<img src="images/goods/goods003.jpg" alt="商品图片">
<h4>商品名称手机</h4>
<div>6</div>
</li>
</ul>
</div>
</div>
<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="pos_center_con clearfix">
<ul class="slide">
{% for content in contents.index_lbt %}
<li><a href="{{ content.url }}"><img src="{{ content.image.url }}" alt="{{ content.title }}"></a></li>
{% endfor %}
</ul>
<div class="prev"></div>
<div class="next"></div>
<ul class="points">
<!-- <li class="active"></li>
<li></li>
<li></li>
<li></li> -->
</ul>
<ul class="sub_menu">
{% for group in categories.values %}
<li>
<div class="level1">
{% for channel in group.channels %}
<a href="{{ channel.url }}">{{ channel.name }}</a>
{% endfor %}
</div>
<div class="level2">
{% for cat2 in group.sub_cats %}
<div class="list_group">
<div class="group_name fl">{{cat2.name}} ></div>
<div class="group_detail fl">
{% for cat3 in cat2.sub_cats %}
<a href="/list.html?cat={{cat3.id}}">{{cat3.name}}</a>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
</li>
{% endfor %}
</ul>
<div class="news">
<div class="news_title">
<h3>快讯</h3>
<a href="#">更多 ></a>
</div>
<ul class="news_list">
{% for content in contents.index_kx %}
<li><a href="{{ content.url }}">{{ content.title }}</a></li>
{% endfor %}
</ul>
{% for content in contents.index_ytgg %}
<a href="{{ content.url }}" class="advs"><img src="{{ content.image.url }}"></a>
{% endfor %}
</div>
</div>
<div class="list_model">
<div class="list_title clearfix">
<h3 class="fl" id="model01">1F 手机通讯</h3>
<div class="subtitle fr">
<a @mouseenter="f1_tab=1" :class="f1_tab===1?'active':''">时尚新品</a>
<a @mouseenter="f1_tab=2" :class="f1_tab===2?'active':''">畅想低价</a>
<a @mouseenter="f1_tab=3" :class="f1_tab===3?'active':''">手机配件</a>
</div>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl">
<img src="{{ contents.index_1f_logo.0.image.url }}">
<div class="channel">
{% for content in contents.index_1f_pd %}
<a href="{{ content.url }}">{{ content.title }}</a>
{% endfor %}
</div>
<div class="key_words">
{% for content in contents.index_1f_bq %}
<a href="{{ content.url }}">{{ content.title }}</a>
{% endfor %}
</div>
</div>
<ul v-show="f1_tab===1" class="goods_list fl">
{% for content in contents.index_1f_ssxp %}
<li>
<a href="{{ content.url }}" class="goods_pic"><img src="{{ content.image.url }}"></a>
<h4><a href="{{ content.url }}" title="{{ content.title }}">{{ content.title }}</a></h4>
<div class="prize">{{ content.text }}</div>
</li>
{% endfor %}
</ul>
<ul v-show="f1_tab===2" class="goods_list fl">
{% for content in contents.index_1f_cxdj %}
<li>
<a href="{{ content.url }}" class="goods_pic"><img src="{{ content.image.url }}"></a>
<h4><a href="{{ content.url }}" title="{{ content.title }}">{{ content.title }}</a></h4>
<div class="prize">{{ content.text }}</div>
</li>
{% endfor %}
</ul>
<ul v-show="f1_tab===3" class="goods_list fl">
{% for content in contents.index_1f_sjpj %}
<li>
<a href="{{ content.url }}" class="goods_pic"><img src="{{ content.image.url }}"></a>
<h4><a href="{{ content.url }}" title="{{ content.title }}">{{ content.title }}</a></h4>
<div class="prize">{{ content.text }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="list_model model02">
<div class="list_title clearfix">
<h3 class="fl" id="model01">2F 电脑数码</h3>
<div class="subtitle fr">
<a @mouseenter="f2_tab=1" :class="f2_tab===1?'active':''">加价换购</a>
<a @mouseenter="f2_tab=2" :class="f2_tab===2?'active':''">畅享低价</a>
</div>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl">
<img src="{{ contents.index_2f_logo.0.image.url}}">
<div class="channel">
{% for content in contents.index_2f_pd %}
<a href="{{ content.url }}">{{ content.title }}</a>
{% endfor %}
</div>
<div class="key_words">
{% for content in contents.index_2f_bq %}
<a href="{{ content.url }}">{{ content.title }}</a>
{% endfor %}
</div>
</div>
<ul v-show="f2_tab===1" class="goods_list fl">
{% for content in contents.index_2f_jjhg %}
<li>
<a href="{{ content.url }}" class="goods_pic"><img src="{{ content.image.url }}"></a>
<h4><a href="{{ content.url }}" title="{{ content.title }}">{{ content.title }}</a></h4>
<div class="prize">{{ content.text }}</div>
</li>
{% endfor %}
</ul>
<ul v-show="f2_tab===2" class="goods_list fl">
{% for content in contents.index_2f_cxdj %}
<li>
<a href="{{ content.url }}" class="goods_pic"><img src="{{ content.image.url }}"></a>
<h4><a href="{{ content.url }}" title="{{ content.title }}">{{ content.title }}</a></h4>
<div class="prize">{{ content.text }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="list_model model03">
<div class="list_title clearfix">
<h3 class="fl" id="model01">3F 家居家装</h3>
<div class="subtitle fr">
<a @mouseenter="f3_tab=1" :class="f3_tab===1?'active':''">生活用品</a>
<a @mouseenter="f3_tab=2" :class="f3_tab===2?'active':''">厨房用品</a>
</div>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl">
<img src="{{ contents.index_3f_logo.0.image.url }}">
<div class="channel">
{% for content in contents.index_3f_pd %}
<a href="{{ content.url }}">{{ content.title }}</a>
{% endfor %}
</div>
<div class="key_words">
{% for content in contents.index_3f_bq %}
<a href="{{ content.url }}">{{ content.title }}</a>
{% endfor %}
</div>
</div>
<ul v-show="f3_tab===1" class="goods_list fl">
{% for content in contents.index_3f_shyp %}
<li>
<a href="{{ content.url }}" class="goods_pic"><img src="{{ content.image.url }}"></a>
<h4><a href="{{ content.url }}" title="{{ content.title }}">{{ content.title }}</a></h4>
<div class="prize">{{ content.text }}</div>
</li>
{% endfor %}
</ul>
<ul v-show="f3_tab===2" class="goods_list fl">
{% for content in contents.index_3f_cfyp %}
<li>
<a href="{{ content.url }}" class="goods_pic"><img src="{{ content.image.url }}"></a>
<h4><a href="{{ content.url }}" title="{{ content.title }}">{{ content.title }}</a></h4>
<div class="prize">{{ content.text }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
<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>
</div>
<script type="text/javascript" src="js/index.js"></script>
</body>
</html>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
新建scripts目录(存储静态化首页的手动脚本)
regenerate_index_html.py
#!/usr/bin/env python
import sys
sys.path.insert(0, '../')
sys.path.insert(0, '../apps')
import os
if not os.getenv('DJANGO_SETTINGS_MODULE'):
os.environ['DJANGO_SETTINGS_MODULE'] = 'mall.settings'
# 让django进行初始化设置
import django
django.setup()
from contents.crons import generate_static_index_html
if __name__ == '__main__':
generate_static_index_html()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
为脚本添加可执行权限
chmod +x regenerate_index_html.py
- 1
测试执行
下一步 定时任务
对于首页的静态化,考虑到页面的数据可能由多名运营人员维护,并且经常变动,所以将其做成定时任务,即定时执行静态化
在Django执行定时任务,可以通过django-crontab扩展来实现。
安装
pip install django-crontab
- 1
在settings中添加任务
INSTALLED_APPS = [
...
'django_crontab', # 定时任务
...
]
- 1
- 2
- 3
- 4
- 5
设置任务的定时时间
在配置文件中设置定时执行的时间
每个定时任务分为三部分定义:
任务时间
基本格式 :
* * * * *
分 时 日 月 周 命令
M: 分钟(0-59)。每分钟用*或者 */1表示
H:小时(0-23)。(0表示0点)
D:天(1-31)。
m: 月(1-12)。
d: 一星期内的天(0~6,0为星期天)。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
添加任务到settings中
# 定时任务
CRONJOBS = [
# 每5分钟执行一次生成主页静态文件
('*/5 * * * *', 'contents.crons.generate_static_index_html', '>> /home/python/Desktop/meiduo/mall/logs/crontab.log')
]
- 1
- 2
- 3
- 4
- 5
遇到问题
在定时任务中,如果出现非英文字符,会出现字符异常错误
可以通过在配置文件中添加定时任务执行的附加命令来实现
# 解决crontab中文问题
CRONTAB_COMMAND_PREFIX = 'LANG_ALL=zh_cn.UTF-8'
- 1
- 2
开启定时任务
添加定时任务到系统中
python manage.py crontab add
- 1
显示已经激活的定时任务
python manage.py crontab show
- 1
移除定时任务
python manage.py crontab remove
- 1