在图片存储功能中实用到了FastDFS分布式文件存储系统
在项目中使用fastfds分布式文件存储系统时,要修改django的上传行为,进行二次开发
在utils python package下创建fastfds python package然后在fastdfs下创建storage.py
from django.core.files.storage import Storage
from django.conf import settings
from fdfs_client.client import Fdfs_client
class FDFSStorage(Storage):
'''fast dfs文件存储类'''
def __init__(self, client_conf=None, base_url=None):
'''初始化'''
if client_conf is None:
client_conf = settings.FDFS_CLIENT_CONF
self.client_conf = client_conf
if base_url is None:
base_url = settings.FDFS_URL
self.base_url = base_url
def _open(self, name, mode='rb'):
'''打开文件时使用'''
pass
def _save(self, name, content):
'''保存文件时使用'''
# name:你选择上传文件的名字
# content:包含你上传文件内容的File对象
# 创建一个Fdfs_client对象
client = Fdfs_client(self.client_conf)
# 上传文件到fast dfs系统中
res = client.upload_by_buffer(content.read())
# dict
# {
# 'Group name': group_name,
# 'Remote file_id': remote_file_id,
# 'Status': 'Upload successed.',
# 'Local file name': '',
# 'Uploaded size': upload_size,
# 'Storage IP': storage_ip
# }
if res.get('Status') != 'Upload successed.':
# 上传失败
raise Exception('上传文件到fast dfs失败')
# 获取返回的文件ID
filename = res.get('Remote file_id')
# 返回值会保存在image字段中
return filename
def exists(self, name):
'''Django判断文件名是否可用'''
return False
def url(self, name):
'''返回访问文件的url路径'''
return self.base_url+name
注意应为
还需要在settings中添加一些设置
# 设置Django的文件存储类
DEFAULT_FILE_STORAGE='utils.fastdfs.storage.FDFSStorage'
# 设置fdfs使用的client.conf文件路径
FDFS_CLIENT_CONF='./utils/fastdfs/client.conf'
# 设置fdfs存储服务器上nginx的IP和端口号
FDFS_URL='http://127.0.0.1:8888/'
然后在user.admin.py重注册类然后在后台进行测试,需要注意的是,当你修改了image字段的的默认存储方式,那么当你渲染模板要使用image时,要在src下写"{{goods.image.url}}"
接下来因为考虑到当用户基数较大时,如果一开始访问域名就和数据库服务交互会对服务器产生很大的压力,所以利用celery动态生成静态页面,并利用nginx收集静态页面
首先在celery_tasks/tasks.py中添加任务
@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') as f:
f.write(static_index_html)
接下来在celery上部署nginx服务,利用Nginx的代理服务提供静态页面要在nginx.conf中添加新服务
location / {
# root html;
root /home/tarena/dailyfresh/mydailyfresh/mydailyfresh/static/;
index index.html index.htm;
}
root 后要跟你项目的绝对路径,以及静态文件所在的文件夹
index 后面写你的项目文件名,如果没有找到前面的就默认返回index.html
因为考虑到当管理员通过管理页面修改了首页对应表数据时,要更新静态页面所以需要对django的modelmanager进行二次开发在goods/admin.py中添加如下代码:
from django.contrib import admin
from django.core.cache import cache
from goods.models import GoodsType,IndexPromotionBanner,IndexGoodsBanner,IndexTypeGoodsBanner
# Register your models here.
class BaseModelAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
'''新增或更新表中的数据时调用'''
# 调先用父类的save_model方法进行数据修改
super().save_model(request, obj, form, change)
# 发出任务,让celery worker重新生成首页静态页
from celery_tasks.tasks import generate_static_index_html
generate_static_index_html.delay()
# 清除首页的缓存数据
cache.delete('index_page_data')
def delete_model(self, request, obj):
'''删除表中的数据时调用'''
super().delete_model(request, obj)
# 发出任务,让celery worker重新生成首页静态页
from celery_tasks.tasks import generate_static_index_html
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(IndexGoodsBanner, IndexGoodsBannerAdmin)
admin.site.register(IndexTypeGoodsBanner, IndexTypeGoodsBannerAdmin)
admin.site.register(IndexPromotionBanner, IndexPromotionBannerAdmin)
动态网站的基本权衡点就是,它是动态的。 每次用户请求页面,服务器会重新计算。从开销处理的角度来看,这比你读取一个现成的标准文件的代价要昂贵的多。
以为首页要用到的数据较多,如果每一次访问首页都查询数据库的话对服务器压力是很大的,所以这里要将首页数据进行缓存,这里采用的方法是操作django的底层缓存api具体代码如下
from django.shortcuts import render, redirect
from django.core.urlresolvers import reverse
from django.views.generic import View
from django.core.cache import cache
from django.core.paginator import Paginator
from goods.models import GoodsType, GoodsSKU, IndexGoodsBanner,IndexPromotionBanner,IndexTypeGoodsBanner
from django_redis import get_redis_connection
from order.models import OrderGoods
# Create your views here.
# class Test(object):
# def __init__(self):
# self.name = 'abc'
#
# t = Test()
# t.age = 10
# print(t.age)
# http://127.0.0.1:8000
class IndexView(View):
'''首页'''
def get(self, request):
'''显示首页'''
# 尝试从缓存中获取数据
context = cache.get('index_page_data')
if context is None:
print('设置缓存')
# 缓存中没有数据
# 获取商品的种类信息
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}
# 设置缓存
# key value timeout
cache.set('index_page_data', context, 3600)
# 获取用户购物车中商品的数目
user = request.user
cart_count = 0
if user.is_authenticated():
# 用户已登录
conn = get_redis_connection('default')
cart_key = 'cart_%d'%user.id
cart_count = conn.hlen(cart_key)
# 组织模板上下文
context.update(cart_count=cart_count)
# 使用模板
return render(request, 'index.html', context)
考虑到缓存需要更新,这里假设当管理员在后台更改首页需要用到的数据时,更新缓存所以要在
from django.contrib import admin
from django.core.cache import cache
from goods.models import GoodsType,IndexPromotionBanner,IndexGoodsBanner,IndexTypeGoodsBanner
# Register your models here.
class BaseModelAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
'''新增或更新表中的数据时调用'''
super().save_model(request, obj, form, change)
# 发出任务,让celery worker重新生成首页静态页
from celery_tasks.tasks import generate_static_index_html
generate_static_index_html.delay()
# 清除首页的缓存数据
cache.delete('index_page_data')
def delete_model(self, request, obj):
'''删除表中的数据时调用'''
super().delete_model(request, obj)
# 发出任务,让celery worker重新生成首页静态页
from celery_tasks.tasks import generate_static_index_html
generate_static_index_html.delay()
# 清除首页的缓存数据
cache.delete('index_page_data')