• DJANGO-天天生鲜项目从0到1-007-首页静态化与缓存


    页面静态化

    为什么需要静态化首页

    主页是一个网站被访问次数最多的页面,且不管用户登不登陆都可以访问,每次访问主页时,都需要从数据库中查询数据,而且每次访问几乎展示的内容都是一样的,除非后台管理员修改了主页的数据信息。

    所以可以将主页单独做出来一个静态的页面(其中包括了数据信息),让未登录的用户直接访问该页面,这样就能够减少服务器的压力。

    又因为该页面是静态写死的,如果后台数据变化了,这个页面的信息也还是原来的信息,为了解决这个问题,保持静态页面的数据是最新的,可以在后台管理员每次修改了首页数据信息时,重新生成新的静态页面。

    如何生成静态化页面

    当管理员每次更新首页需要的数据时,就可以调用生成静态化页面的方法,而这时,如果生成静态化页面处理时间比较长,那么可能会造成管理员前台长时间的等待,因此可以通过celery来进行异步的生成页面。

    celery的配置与‘DJANGO-天天生鲜项目从0到1-002-用户模块-注册’中的利用celery一样,因此在其基础上的tasks.py文件上新增一个任务即可。

    获取首页数据

    因为获取首页的数据在多个地方都需要使用到,因此将其封装成一个方法,与上一节的获取购物车数量一样,放在utils/utils.py中:

    from goods.models import *

    def
    get_index_data(): '''获取首页数据信息''' # 获取商品分类 goods_type = GoodsType.objects.all() # 获取轮播商品 goods_banner = IndexGoodsBanner.objects.all().order_by('index') # 获取活动信息 promotion_banner = IndexPromotionBanner.objects.all().order_by('index') # 获取分类商品展示信息 for goodstype in goods_type: # 获取该类型下面的商品的标题信息,并进行排序 title_banner = IndexTypeGoodsBanner.objects.filter(goodstype=goodstype, display_type=0).order_by('index') # 获取该类型下面的商品的图片信息,并进行排序 image_banner = IndexTypeGoodsBanner.objects.filter(goodstype=goodstype, display_type=1).order_by('index') # 动态给type增加属性,分别保存首页分类商品的文字信息和图片信息 goodstype.title_banner = title_banner goodstype.image_banner = image_banner # 组织上下文 context = { 'goods_type': goods_type, 'goods_banner': goods_banner, 'promotion_banner': promotion_banner, } return context

    创建celery任务

    获取数据后,仍然使用goods/index.html模板文件,使用模板对象的render方法将获取到的数据填入模板文件中生成html内容,再通过with open将html内容写入至static下的index.html文件中,这里需要先创建出该空文件。

    from utils.utils import get_index_data
    from django.template import loader
    
    @app.task()
    def generate_static_index():
        # 获取需要展示的信息
        context = get_index_data()
        # 使用模板
        # 加载模板文件,返回模板对象
        template = loader.get_template('goods/index.html')
        # 渲染模板
        static_index = template.render(context)
    
        # 生成html文件
        save_path = os.path.join(settings.BASE_DIR, 'static/index.html')
        with open(save_path, 'w') as f:
            f.write(static_index)

    创建admin模型管理类,调用celery任务

    我们需要后台管理员在修改了首页数据信息时调用创建静态文件的celery任务,因此需要用到admin模型管理类,重写相关模型类的save和delete方法

    编辑goods/admin.py文件:

    from django.contrib import admin
    from goods.models import *
    from utils.tasks import generate_static_index
    from django.core.cache import cache
    # Register your models here.
    
    class BaseModelAdmin(admin.ModelAdmin):
        '''模型管理站点'''
        def save_model(self, request, obj, form, change):
            # 继承父类方法
            super().save_model(request, obj, form, change)
            # 调用celery重新生成静态首页文件
            generate_static_index.delay()
            # 清除缓存
            cache.delete('index_data')
    
        def delete_model(self, request, obj):
            # 继承父类方法
            super().delete_model(request, obj)
            # 调用celery重新生成静态首页文件
            generate_static_index.delay()
            # 清除缓存
            cache.delete('index_data')
    
    admin.site.register(Goods, BaseModelAdmin)
    admin.site.register(GoodsSPU, BaseModelAdmin)
    admin.site.register(GoodsType, BaseModelAdmin)
    admin.site.register(GoodsImage, BaseModelAdmin)
    admin.site.register(IndexGoodsBanner, BaseModelAdmin)
    admin.site.register(IndexTypeGoodsBanner, BaseModelAdmin)
    admin.site.register(IndexPromotionBanner, BaseModelAdmin)

    通过Nginx访问静态页面

    上面生成的静态页面只能够通过django服务器ip:8000/static/index.html网址访问,但是我们想要的是用户直接输入ip地址后就能访问静态页面,于是需要Nginx帮忙。在Nginx配置文件(/usr/local/nginx/conf/nginx.conf)中,修改如下配置:

    server {
            listen       80;
            server_name  localhost;
            #charset koi8-r;
            #access_log  logs/host.access.log  main;
            location /static {
                alias /home/gong/study/projects/dailyfresh/static/;
            }
            location / {
                #root   html;
                root /home/gong/study/projects/dailyfresh/static/;
                index index.html index.htm;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }

    在浏览器中输入IP地址后不输入端口号时,则默认访问的是80端口,location相当于是url匹配器,从上往下进行匹配,若符合ip/static,则显示 /home/gong/study/projects/dailyfresh/static/ 下面的index.html文件,若ip地址后面什么都没有输入,则也显示/home/gong/study/projects/dailyfresh/static/下面的index%文件

    在浏览器中输入http://192.168.183.129/static/http://192.168.183.129时访问的就是生成的静态页面

    何时访问静态化首页,何时访问正常动态化的首页

    当我们访问静态化首页时,访问的地址是http://192.168.183.129,默认的是80端口,访问到的服务器是Nginx服务器

    当我们访问动态化首页时,访问的地址是http://192.168.183.129:8000,是8000端口,访问到的是服务器是Django服务器

    但是部署上线后,最后暴露给用户的地址肯定只有一个,而不是将上述两个地址给用户,让用户选择访问哪个页面,这里就需要在用户和(Nginx、Django)服务器之间,再搭一台Nginx服务器,通过这台Nginx服务器给用户暴露一个浏览的地址(比如为http://192.168.183.130),然后让服务器判断决定用户最终访问的服务器是哪个(比如当用户直接输入http://192.168.183.130时,中间的Nginx最终让其访问的是Nginx指向的静态首页,当用户输入http://192.168.183.130/index时,中间的Nginx最终让其访问的是Django服务器的动态首页)。

    缓存首页数据信息

    当我们不是访问静态页面的首页,而是访问正常动态首页时,每次访问也依然需要重新查询数据库,而其实查出来的数据基本都是一样的,除非后台管理员修改了后台数据,这时为了避免重复查询,可以使用django的缓存机制,将第一次查出来的数据放入django服务器的缓存中(注意不是浏览器的缓存),后续访问页面时,先在缓存中查询数据是否存在,存在即直接取出数据,不存在即重新查询数据。

    配置django缓存

    缓存可以存在数据库或者文件系统中,一般我们都会存在内存型数据库汇总,前面登录配置session时(DJANGO-天天生鲜项目从0到1-003-用户模块-登录),已经配好了将缓存存在redis数据库中

    CACHES = {
      "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
          "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
      }
    }

    使用django缓存,cache.get(key),cache.set(key, data, timeout)

    在首页view.py中,在查询数据库信息前,先通过cache.get从缓存中查询是否存在需要的数据,若不存在则在查询完一些公用的数据库信息之后,将这些公用信息通过cache.set存在缓存中

    from django.core.cache import cache
    
    class IndexView(View):
        '''首页视图'''
        template_name = 'goods/index.html'
        def get(self, request):
            '''显示首页'''
            # 从缓存汇总获取数据
            context = cache.get('index_data')
            if not context:
                # 获取数据库信息
                context = get_index_data()
                # 设置缓存,3600秒过期
                print('设置缓存')
                cache.set('index_data', context, 3600)
    
            # 获取购物车数量,购物车存储格式为:cart_userid : {'goodsid': quantity}
            cart_count = get_cart_count(request)
            context['cart_count'] = cart_count
            return render(request, self.template_name, context)

    删除缓存,cache.delete(key)

    同样在后台管理员修改了首页数据库信息时,需要将原来的缓存删除掉,等删除后再次访问首页时,重新设置新的缓存信息

    from django.core.cache import cache
    
    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')
     
  • 相关阅读:
    正经学C#_循环[do while,while,for]:[c#入门经典]
    Vs 控件错位 右侧资源管理器文件夹点击也不管用,显示异常
    asp.net core 获取当前请求的url
    在实体对象中访问导航属性里的属性值出现异常“There is already an open DataReader associated with this Command which must be
    用orchard core和asp.net core 3.0 快速搭建博客,解决iis 部署https无法登录后台问题
    System.Data.Entity.Core.EntityCommandExecution The data reader is incompatible with the specified
    初探Java设计模式3:行为型模式(策略,观察者等)
    MySQL教程77-CROSS JOIN 交叉连接
    MySQL教程76-HAVING 过滤分组
    MySQL教程75-使用GROUP BY分组查询
  • 原文地址:https://www.cnblogs.com/gcxblogs/p/12813541.html
Copyright © 2020-2023  润新知