【Django 天天生鲜项目03】FastDFS文件存储-首页-详情页-列表页(FastDFS、页面静态化、缓存设置和获取...)

本文详细介绍了如何在Django项目中集成FastDFS实现文件存储,包括FastDFS的安装配置、Python客户端的使用。同时讲解了首页静态化、数据缓存设置和获取,以及使用Celery生成静态页面。此外,还涵盖了Nginx配置以提供静态页面和FastDFS文件。文章最后提到了详情页的历史浏览记录和列表页的数据分页处理。
摘要由CSDN通过智能技术生成

关键:FastDFS分布式文件存储、页面静态化、celery、Nginx提供页面、数据缓存设置和获取、缓存数据(历史浏览)、页码控制

仅作为个人笔记!

目录

1.FastDFS文件存储

1.2.FastDFS安装

1.3.使用python客户端上传测试

1.4.FastDFS配置文件的修改

2.Django项目中使用FastDFS

2.1.Django项目中使用FastDFS的流程

2.2. 自定义文件存储类对接FastDFS

3.网站首页

3.1.首页静态化

3.3.数据缓存设置和获取

4.详情页-添加历史浏览记录

对数据进行分页


1.FastDFS文件存储

若图片等文件都保存在Django的服务器中,但是服务器的硬盘的容量是有限的,而且服务器的容量昂贵。容量和成本都会受到限制。需要保存大量的文件时,通常会有一个专门的文件存储的服务器。

1.1.什么是FastDFS?

简介

FastDFS 是用 c 语言编写的一款开源的分布式文件系统。FastDFS 为互联网量身定制, 充分考了冗余份、负载均衡、线容等机制,并注重高可用、高性能等指,使用 FastDFS 很容易搭建一套高性能的文件服器集群提供文件上、下等服

FastDFS 架构包括 Tracker server Storage server。客户端请求 Tracker server 进行文 件上传、下载,通过 Tracker server 调度最终由 Storage server 完成文件上传和下载。

Tracker server 作用是负载均衡和调度,通过 Tracker server 在文件上传时可以根据一些 策略找到 Storage server 提供文件上传服务。可以将 tracker 称为追踪服务器或调度服务器

Storage server 作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上, Storageserver 没有实现自己的文件系统而是利用操作系统 的文件系统来管理文件。可以将 storage 称为存储服务器Storage有不同的组,组中的机器可以进行相互的备份,不同的组之间可以保存不同的数据。可以通过扩展组来方便的扩展容量。

Storage保存文件时,保存的不是简单的文件名,而是对文件的内容取哈希值(唯一的值,就像文件的指纹),再结合其他信息生成文件名。这样,不同的用户上传相同的文件(文件名可能不同,但哈希值是一样的)时,相同的文件在Storage中只需存储一份(文件去重还需要配置:【FastDFS】FastDFS+FastDHT完成文件上传去重_fastdfs 图片重复提交怎么办-CSDN博客

优点:文件的海量存储、存储容量方便扩展、文件内容防止重复。

Tracker管理集群,tracker 也可以实现集群。每个 tracker 节点地位平等。收集 Storage 集群的状态。

Storage实际保存文件 Storage 分为多个组,每个组之间保存的文件是不同的。每 个组内部可以有多个成员,组成员内部保存的内容是一样的,组成员的地位是一致的,没有主从的概念。

保存文件ID的相关名词

  • 组名:文件上传后所在的 storage 组名称,在文件上传成功后有 storage 服务器返回, 需要客户端自行保存。
  • 虚拟磁盘路径:storage 配置的虚拟路径,与磁盘选项 store_path*对应。如果配置了 store_path0 则是 M00,如果配置了 store_path1 则是 M01,以此类推。
  • 数据两级目录:storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据 文件。
  • 文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储 服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

上传流程

  1. Storage会定时向tracker 发送心跳连接。

  2. client上传文件,请求tracker,tracker调度一个Storage的组,返回Storage的ip和端口给client;

  3. client根据返回来请求Storage,上传文件;

  4. Storage保存文件,生成文件file_id,并返回;

  5. 客户端接收到file_id并保存。

客户端上传文件后存储服务器将文件 ID 返回给客户端,此文件 ID 用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。类似:group1/M00/00/00/rBIK6VcaP0aARXXvAAHrUgHEviQ394

下载流程

简单的FastDFS架构

1.2.FastDFS安装

1.2.1.安装fastdfs依赖包

1. 解压缩libfastcommon-master.zip:unzip libfastcommon-master.zip

2. 进入到libfastcommon-master的目录中

3. 执行 ./make.sh

4. 执行 sudo ./make.sh install

1.2.2. 安装fastdfs

1. 解压缩fastdfs-master.zip :unzip fastdfs-master.zip

2. 进入到 fastdfs-master目录中

3. 执行 ./make.sh

4. 执行 sudo ./make.sh install

1.2.3.配置跟踪服务器tracker

1. sudo cp /etc/fdfs/tracker.conf.sample /etc/fdfs/tracker.conf

2. 在/home/python/目录中创建目录 fastdfs/tracker     

sudo mkdir –p /home/python/fastdfs/tracker

3. 编辑/etc/fdfs/tracker.conf配置文件   

sudo vim /etc/fdfs/tracker.conf

修改: base_path=/home/python/fastdfs/tracker

1.2.4.配置存储服务器storage

1. sudo cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf

2. 在/home/python/fastdfs/ 目录中创建目录 storage

   sudo mkdir –p /home/python/fastdfs/storage

3. 编辑/etc/fdfs/storage.conf配置文件 

sudo vim /etc/fdfs/storage.conf

修改内容:

base_path=/home/python/fastdfs/storage

store_path0=/home/python/fastdfs/storage

tracker_server=自己ubuntu的ip地址:22122

这样配置后,/home/python/fastdfs/storage  即为文件的存储目录

1.2.5. 启动tracker 和 storage

sudo service fdfs_trackerd start

sudo service fdfs_storaged start

这一步,如果系统报类似错误:

Failed to start fdfs_trackerd.service: Unit fdfs_trackerd.service not found 

填坑更新解决方法(我在腾讯云部署时报错)

改为使用下面的命令启动:

/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf start 
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf start

重启命令:

/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart

如果报 Permission denied,那就以sudo运行,或修改权限。

或尝试下面的方法:

方法一:重启大法好。

方法二:如果是虚拟机,关闭虚拟机,更换网络连接方式为NAT,再次启动会发现,不报错了。如果上传文件时又报错了,这时候再次关闭虚拟机,网络连接方式切换成原来的桥接。

方法三:在服务器配置时,storaged可能会启动失败,需要配置云服务器实例安全组,添加安全组配置,打开22122和23000端口。

然后关闭系统防火墙:systemctl stop firewalld.service。

启动成功后可以配置开机自动启动

sudo vim /etc/rc.local

在打开的文件中添加:

/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart

/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart

退出保存即可。

1.2.6. 测试是否安装成功

1. sudo cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf

2. 编辑/etc/fdfs/client.conf配置文件 

sudo vim /etc/fdfs/client.conf

修改内容:

base_path=/home/python/fastdfs/tracker

tracker_server=自己ubuntu虚拟机的ip地址:22122

3. 上传文件测试:

fdfs_upload_file 指定配置文件 要上传的图片文件

如:fdfs_upload_file /etc/fdfs/client.conf ~/Desktop/fruit.jpg

返回如下的文件id,则上传成功。

python@ubuntu:~$ fdfs_upload_file /etc/fdfs/client.conf ~/Desktop/fruit.jpg
group1/M00/00/00/wKgryl6TH-CAV9HuAASpN5uHrDU002.jpg

1.2.7. 安装nginx及fastdfs-nginx-module

fastDFS在用户量比较大时,对于文件的获取效率是比较慢的。可以借助nginx web服务器来提高效率。Nginx可以配合FastDFS来使用,而且Nginx在提供静态文件的效率很高。Nginx服务器在接收请求的时候使用的 epoll 

所以上传的文件的时候可以使用FastDFS,获取文件的时候还需要借助Nginx服务器。

1. 解压缩 nginx-1.8.1.tar.gz

tar -zxvf nginx-1.8.1.tar.gz

2. 解压缩 fastdfs-nginx-module-master.zip

unzip fastdfs-nginx-module-master.zip

3. cd进入nginx-1.8.1目录

4. 执行

sudo ./configure --prefix=/usr/local/nginx/ --add-module=fastdfs-nginx-module-master解压后的目录的绝对路径/src

如:(注:pwd可查看当前目录的绝对路径)

sudo ./configure --prefix=/usr/local/nginx/ --add-module=/home/python/Desktop/new/fastdfs-nginx-module-master/src

如果报错:./configure: error: the HTTP rewrite module requires the PCRE library.

把库装上:sudo apt-get install libpcre3 libpcre3-dev

sudo make

sudo make install

5. 复制到指定目录

sudo cp fastdfs-nginx-module-master解压后的目录中src下的mod_fastdfs.conf  /etc/fdfs/mod_fastdfs.conf

如:

sudo cp /home/python/Desktop/new/fastdfs-nginx-module-master/src/mod_fastdfs.conf /etc/fdfs/mod_fastdfs.conf

6.修改配置 

sudo vim /etc/fdfs/mod_fastdfs.conf

修改内容:

connect_timeout=10

tracker_server=自己ubuntu虚拟机的ip地址:22122

url_have_group_name=true

store_path0=/home/python/fastdfs/storage

7.

sudo cp 解压缩的fastdfs-master目录下conf目录中的http.conf  /etc/fdfs/http.conf

如:

sudo cp /home/python/Desktop/new/fastdfs-master/conf/http.conf /etc/fdfs/http.conf

8.

sudo cp 解压缩的fastdfs-master目录下conf目录中的mime.types /etc/fdfs/mime.types

如:

sudo cp /home/python/Desktop/new/fastdfs-master/conf/mime.types /etc/fdfs/mime.types

9.编辑Nginx配置文件

sudo vim /usr/local/nginx/conf/nginx.conf

在http部分中添加配置信息如下:

server {
            listen       8888;  # 监听端口号
            server_name  localhost;  # 服务器域名
            location ~/group[0-9]/ {
                ngx_fastdfs_module;
            }
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
            root   html;
            }
        }

10. 启动nginx

sudo nginx的启动文件

sudo /usr/local/nginx/sbin/nginx

sudo /usr/local/nginx/sbin/nginx -s reload  # 重启

关闭Nginx:

sudo /usr/local/nginx/sbin/nginx -s stop

或:

sudo /usr/local/nginx/sbin/nginx -s quit

使用 ip:port/返回的文件id 就可以访问文件,如:

http://127.0.0.1:8888/group1/M00/00/00/wKgryl6TH-CAV9HuAASpN5uHrDU002.jpg

1.3.使用python客户端上传测试

python和FastDFS的交互需要安装相关的包。

  1. 进去虚拟环境,进入fdfs_client-py-master.zip所在目录
  2. pip install fdfs_client-py-master.zip

>>> from fdfs_client.client import Fdfs_client

>>> client = Fdfs_client('/etc/fdfs/client.conf')  # 指定client.conf文件创建类的对象

>>> ret = client.upload_by_filename('test')  # upload_by_filename方法根据文件名上传文件

>>> ret  # 返回值是一个字典

{'Group name':'group1','Status':'Upload successed.', 'Remote file_id':'group1/M00/00/00/

         wKjzh0_xaR63RExnAAAaDqbNk5E1398.py','Uploaded size':'6.0KB','Local file name':'test'

         , 'Storage IP':'192.168.243.133'}

返回值是一个字典,包含是否上传成功,以及返回的文件id。

文档 https://github.com/JaceHo/fdfs_client-py

1.4.FastDFS配置文件的修改

启动FastDFS的方法,需要的操作

1. 修改如下标红的配置文件  (在/etc/fdfs目录中)

python@ubuntu:/etc/fdfs$ ls
client.conf         http.conf   mod_fastdfs.conf  storage.conf.sample      tracker.conf
client.conf.sample  mime.types  storage.conf      storage_ids.conf.sample  tracker.conf.sample

修改三个配置文件的:tracker_server=己的ip:22122

2.启动tracker、storage、nginx这三个服务

sudo service fdfs_trackerd start

sudo service fdfs_storaged start

sudo /usr/local/nginx/sbin/nginx

修改了配置文件重启才生效,重启的命令如下

sudo service fdfs_trackerd restart
sudo service fdfs_storaged restart
sudo /usr/local/nginx/sbin/nginx -s stop(或quit)
sudo /usr/local/nginx/sbin/nginx
( sudo /usr/local/nginx/sbin/nginx -s reload )

3.执行如下命令测试是否成功

fdfs_upload_file 指定配置文件 要上传的图片文件

如:fdfs_upload_file /etc/fdfs/client.conf ~/Desktop/fruit.jpg

如果返回类似group1/M00/00/00/rBIK6VcaP0aARXXvAAHrUgHEviQ394.jpg的文件id则说明文件上传成功

在浏览器中可以用 127.0.0.1:8888/返回的文件id 或 配置的ip:port/返回的文件id 就可以访问图片。

2.Django项目中使用FastDFS

2.1.Django项目中使用FastDFS的流程

  1. 浏览器请求上传文件;
  2. Django把文件上传到FastDFS;
  3. 上传完保存后,FastDFS返回文件的id,Django把文件对应的id保存在对应表的image字段中;

在视图渲染页面的过程中,以图片文件为例,会将image的src渲染成 'http://配置的ip:port/返回的文件id' 这样的格式。再将整个页面返回给页面......浏览器页面再根据src去请求nginx获取图片文件,nginx返回图片文件的内容。

2.2. 自定义文件存储类对接FastDFS

默认时,Django上传文件时,最终保存的时候,使用的是这个类The FileSystemStorage classThe Storage class的子类 的save(name, content, max_length=None)[源代码] 方法来实现保存。默认会将文件保存到MEDIA_ROOT指定的目录下方。

想要将文件保存到FastDFS,就需要自定义文件的存储,但是不能修改 FileSystemStorage的源代码。其实,其父类Storage类预留了一些相应的方法,只要继承与Storage类,然后重写一些里面的方法就可以更改文件存储的行为。

在Django的文档中,提供了编写自定义的文件存储系统的方法编写一个自定义存储系统

1.在项目的utils目录中,新建一个包,比如 fdfs新建文件 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  # FDFS_CLIENT_CONF在setting配置
        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配置文件)
        client = Fdfs_client(self.client_conf)

        # 上传文件到fast dfs系统中
        res = client.upload_by_buffer(content.read())  # 根据内容上传文件

        # @return 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 success else None

        if res.get('Status') != 'Upload successed.':
            raise Exception('上传文件到fast dfs失败')

        # 获取返回的file_ID
        filename = res.get('Remote file_id')
        return filename

    def exists(self, name):
        """Django判断文件名是否可用"""
        return False

    def url(self, name):
        """返回访问文件的url路径"""
        return self.base_url + name  # 加上base_url,即ip和端口号

创建Fdfs_client对象时,要指定client配置文件client.conf,可以将 /etc/fdfs/client.conf 复制一份,并放到项目的目录下,做一些相应修改,关键是以下项

# log files的保存地址
base_path=/home/python/fastdfs/tracker

# tracker_server=host:port, host can be hostname or ip address
tracker_server=192.168.4.202:22122

2. setting中做相应的配置

# 设置Django的文件存储类
DEFAULT_FILE_STORAGE='utils.fdfs.storage.FDFSStorage'

# 设置fdfs使用的client.conf文件路径
FDFS_CLIENT_CONF='./utils/fdfs/client.conf'

# 设置fdfs存储服务器上nginx的IP和端口号
FDFS_URL='http://192.168.4.202:8888/'

3.测试一下

注册有图片或文件的相关模型,在admin上传个文件试试

# goods/admin.py
from django.contrib import admin
from goods.models import GoodsType

admin.site.register(GoodsType)

登录admin,测试上传图片。如果没成功,报类似 No module named 'mutagen' 错误,就在你的环境中用 pip install mutagen 等命令把相关模块装上

3.网站首页

关键:页面的静态化、缓存数据、获取购物车数据、历史浏览记录...

3.1.首页静态化

网站的首页通常是很少变化的。不需要为每一个访问的用户进行定制。可以将首页生成静态页面(页面静态化)。

页面的静态化和显示页面相关的视图关系并不大。可以借助celery来生成首页静态页面:在celery中定义一个任务函数来生成静态的页面。当数据更改时,相关的静态页面才需要重新的生成(比如当管理员后台修改首页信息对应的表格中的数据的时候)。

任务函数:

# 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)

    print(static_index_html)

    # 生成首页对应静态文件
    save_path = os.path.join(settings.BASE_DIR, 'static/index.html')  # 设置生成的目录
    with open(save_path, 'w') as f:
        f.write(static_index_html)  # 将内容写入文件

将代码拷贝一份到worker所在的机器,加入以下语句,启动worker。

# celery_tasks/tasks.py

# 在任务处理者一端加这几句:django环境的初始化
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dailyfresh.settings")
django.setup()
...

在项目目录下,启动celery

方法一:
celery -A celery_tasks.tasks worker -l info 
(celery -A 任务所在的文件 worker -l info )

方法二:守护进程方式启动,日志记录在celerylog.log里(celery_tasks.tasks为我项目任务所在的文件)
celery multi start w1 -A celery_tasks.tasks -l info --logfile=celerylog.log --pidfile=celerypid.pid

停止:celery multi stop w1 -A celery_tasks.tasks -l info

重启:celery multi restart w1 -A celery_tasks.tasks -l info

用下面的代码测试以下,可以看到收到了任务,并生成了静态文件index.html

from celery_tasks.tasks import generate_static_index_html
generate_static_index_html.delay()

注:admin更新数据时重新生成静态页面

在admin后台修改首页使用的数据表的数据时,不仅要把表的数据进行更新,Django还应该让celery重新生成index.html静态页面。

参考:The Django admin siteModelAdmin

每一个后台管理页,都可以定义一个模型管理类(需要继承于ModelAdmin。需要关注两个方法的是ModelAdmin.save_model() 和 ModelAdmin.delete_model()。更新数据时,前者被调用;删除数据时,后者被调用。所以,可以重写这两个方法,在这两个方法中添加额外的操作,使其操作后重新的生成静态文件。因为很多模型都会用到,所以可以抽出来一个父类,其他模型管理类再继承它。

# goods/admin.py
...
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')

3.2.配置nginx提交静态页面

生成的静态文件是在worker所在的机器中的。nginx可以帮助提供FastDFS的图片,类似的,在celery服务器,也可以用nginx在帮助提供静态的页面。

安装好nginx后,编辑Nginx配置文件,在http中再加一个server配置。

sudo vim /usr/local/nginx/conf/nginx.conf

server {
        listen       80;
        server_name  localhost;
        # 最佳匹配
        location /static {
        alias /home/python/Desktop/celery/dailyfresh/static/;
        }
        # 再加一个用作默认匹配
        location / {
            root /home/python/Desktop/celery/dailyfresh/static/;
            index index.html index.htm;
        }

        error_page   500 502 503 504  /50x.html;
            location = /50x.html {
            root   html;
            }
    }

然后重启nginx:

sudo /usr/local/nginx/sbin/nginx -s reload

这样,访问项目服务器的ip地址(默认端口80),就会指向静态化的首页了。

注:静态index页面和IndexView视图的调度(先了解)

网站部署时,在Django中,有一个IndexView视图;在celery服务器中,有一个index.html,nginx服务器帮助提供静态文件。另外还有一个Nginx服务器来进行调度,其只对外暴露一个ip。

  1. 浏览器请求网站,会先请求Nginx;
  2. Nginx决定访问Django视图还是celery生成的静态文件;
  3. 可以配置:若用户访问的是ip地址,则配置其返回静态页面;若访问的是ip/index则返回视图生成的页面。

3.3.数据缓存设置和获取

访问一个页面时,有些数据无论用户是否登录都是一样的。无需每次都进行数据查询。可以通过缓存来进行优化减少数据库查询的次数。缓存可以保存在内存或者redis中,修改了数据库的数据,直接删除缓存,更新缓存,缓存要设置有效期

官方文档!:Django’s cache frameworkDjango’s cache framework(en)设置缓存

缓存配置是通过setting文件的 CACHES 配置来实现的。注意需要的缓存级别。Django提供的三种缓存级别都不适用于首页。这里要手动操作底层的缓存 API,自己来设置和读取实现缓存。

对象和方法:

获取和设置缓存:

# 视图中
......
context = cache.get('index_page_data')  # 获取不到返回None

        if context is None:
            # 获取数据
            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
                image_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=1).order_by('index')
                title_banners = IndexTypeGoodsBanner.objects.filter(type=type, display_type=0).order_by('index')

                type.image_banners = image_banners
                type.title_banners = title_banners

            context = {'types': types,
                       'goods_banners': goods_banners,
                       'promotion_banners': promotion_banners}
            # 设置缓存
            cache.set('index_page_data', context, 3600)
            ......

更新缓存(在admin中改数据后,在重写save_model、delete_model的地方,直接 cache.delete('index_page_data') 清除缓存,让其重新生成即可,参考上面重新生成静态页面)。

小结:页面静态化和缓存对网站有一定的优化作用,能较少对数据的访问,尤其是访问量比较高时,能提高效率。

3.4.首页获取购物车商品数

redis存储购物车记录

  • 用户点击加入购物车时需要添加购物车记录(添加);
  • 使用购物车中数据和访问购物车页面时需要获取购物车记录(获取);
  • 存储购物车记录的格式:一个用户的购物车记录用一条数据保存,用hash类型(属性:值,'cart_用户id':{'sku_id1':商品数目, 'sku_id2':商品数目, ...})记录skuid和数量;

这里获取的数目指的是商品的条数(有多少种),而不是总共多少个。

#  在首页的视图中编辑
        # 获取用户购物车中商品的数目
        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)

4.详情页-添加历史浏览记录

用户登录后,在详情页中,浏览详情页的内容时,添加历史浏览记录。

注:当重复浏览已浏览的记录时,将原来的记录移除,再重新插入到列表左侧中。

redis命令http://redisdoc.com/index.html

redis-py包 文档https://redis-py.readthedocs.io/en/latest/#indices-and-tables

redis列表的一些API lrem(name, count, value)lpush(name, *values)ltrim(name, start, end)、;

# 相关视图中
......            
            # 添加用户的历史记录
            history_key = 'history_%d' % user.id
            # 移除列表中旧的goods_id
            conn.lrem(history_key, 0, goods_id)
            # 把goods_id插入到列表的左侧
            conn.lpush(history_key, goods_id)
            # 只保存用户最新浏览的5条信息
            conn.ltrim(history_key, 0, 4)
......

5.列表页

关键:内容的获取、页码控制

按照前端页面的设计,列表页肯定要获取:种类id、页码、排序方式等参数。注意链接地址的设计,本处采用 "/list/种类id/页码?sort=排序方式 " 的方案。

re_path(r'^list/(?P<type_id>\d+)/(?P<page>\d+)$', ListView.as_view(), name='list'),

对数据进行分页

 官方文档分页

分页需要借助类 Paginator :在视图中使用 PaginatorPaginator 对象

Paginator 类的构造方法是:

class Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True)[源代码] ;前两个为必选参数。

page对象的方法可以判断是否有下一页,包含属性Page.object_list,包含当前页上的对象列表;

相关视图code:

# /list/种类id/页码?sort=排序方式
class ListView(View):
    def get(self, request, type_id, page):
        try:
            type = GoodsType.objects.get(id=type_id)
        except GoodsType.DoesNotExist:
            # 种类不存在,跳转首页
            return render(reverse('goods:index'))

        # 获取商品的分类信息
        types = GoodsType.objects.all()

        sort = request.GET.get('sort')

        if sort == 'price':
            skus = GoodsSKU.objects.filter(type=type).order_by('price')
        elif sort == 'hot':
            skus = GoodsSKU.objects.filter(type=type).order_by('-sales')
        else:
            sort = 'default'
            skus = GoodsSKU.objects.filter(type=type).order_by('-id')

        # 对数据进行分页
        paginator = Paginator(skus, 2)

        # 获取第page页的内容
        try:
            page = int(page)
        except Exception as e:
            page = 1
        if page > paginator.num_pages:
            page = 1

        # 获取第page页的Page实例对象
        skus_page = paginator.page(page)

        # todo: 进行页码的控制,页面上最多显示5个页码
        num_pages = paginator.num_pages
        if num_pages < 5:
            pages = range(1, num_pages+1)
        elif page <= 3:
            pages = range(1, 6)
        elif num_pages-page < 2:
            pages = range(num_pages-4, num_pages+1)
        else:
            pages = range(page-2, page+3)

        # 获取新品信息
        new_skus = GoodsSKU.objects.filter(type=type).order_by('-create_time')[:2]

        # 获取用户购物车中商品的数目
        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 = {'type': type, 'types': types,
                   'skus_page': skus_page,
                   'new_skus': new_skus,
                   'cart_count': cart_count,
                   'pages': pages,
                   'sort': sort}

        return render(request, 'list.html', context)

前端模板相关code:

<div class="pagenation">
                {% if skus_page.has_previous %}
				    <a href="{% url 'goods:list' type.id skus_page.previous_page_number %}?sort={{ sort }}"> <上一页 </a>
                {% endif %}
                {% for pindex in pages %}
                    {% if pindex == skus_page.number %}
				        <a href="{% url 'goods:list' type.id pindex %}?sort={{ sort }}" class="active">{{ pindex }}</a>
                    {% else %}
				        <a href="{% url 'goods:list' type.id pindex %}?sort={{ sort }}">{{ pindex }}</a>
                    {% endif %}
				{% endfor %}
                {% if skus_page.has_next %}
				    <a href="{% url 'goods:list' type.id skus_page.next_page_number %}?sort={{ sort }}">下一页></a>
                {% endif %}
			</div>

01 框架、数据表设计、项目框架笔记

02 注册、登录、用户中心 (itsdangerous模块加密、celery异步、 Django 的验证系统、redis作为缓存等)

03 FastDFS文件存储-首页-详情页-列表页

04 搜索(搜索引擎、分词包的使用)、购物车

05 订单(Mysql事务、并发处理、支付宝支付、评论)

06 项目部署(uwsgi服务器、Nginx服务器)

-----end-----

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值