Django电商项目(四)用户中心、FastDFS

用户中心逻辑

使用父模板改造 用户中心的三个页面
user_center_info.html
user_center_order.html
user_center_site.html

添加view
在这里插入图片描述

导入view后配置url
在这里插入图片描述
view中进行传参
在这里插入图片描述

模板中使用反向解析 并接收参数 判断在哪个页面
在这里插入图片描述

登录装饰器和登录后跳转

只有使用内置的认证系统才能使用的登录装饰器
参考文档:https://doc.codingdict.com/django/topics/auth/default.html#the-login-required-decorator
在这里插入图片描述

导入包使用函数包裹识图
url.py

from django.contrib.auth.decorators import login_required
...

url(r'^$', login_required(UserInfoView.as_view()), name='user'), # 用户中心-信息页
url(r'^order$', login_required(UserOrderView.as_view()), name='order'), # 用户中心-订单页
url(r'^address$', login_required(AddressView.as_view()), name='address'), # 用户中心-地址页

设置未登录状态下跳转不成功 跳回的登录页
settings.py

# 配置登录url地址
LOGIN_URL='/user/login' # 默认为/accounts/login

在这里插入图片描述
未登录状态下进入页面跳回到首页会带着之前页面的url参数
在这里插入图片描述
view.py

在这里插入图片描述

使用LoginRequiredMixin类 完成以上内容
新建utils包
新建mixin.py
在这里插入图片描述
mixin.py

from django.contrib.auth.decorators import login_required


class LoginRequiredMixin(object):
    @classmethod
    def as_view(cls, **initkwargs):
        # 调用父类的as_view
        view = super(LoginRequiredMixin, cls).as_view(**initkwargs)
        return login_required(view)

view导入

from utils.mixin import LoginRequiredMixin

页面进行继承
在这里插入图片描述
url仍使用之前的配置


    url(r'^$', UserInfoView.as_view(), name='user'), # 用户中心-信息页
    url(r'^order$', UserOrderView.as_view(), name='order'), # 用户中心-订单页
    url(r'^address$', AddressView.as_view(), name='address'), # 用户中心-地址页

判断用户是否已登录

在这里插入图片描述
如果用户已登录 request.user.is_authenticated()返回True
在这里插入图片描述
显示欢迎信息 模板文件直接调用user.is_authenticated

在这里插入图片描述

退出登录

在这里插入图片描述

新增退出按钮
在这里插入图片描述
导入logout
from django.contrib.auth import authenticate, login, logout
添加退出视图

# /user/logout
class LogoutView(View):
    '''退出登录'''
    def get(self, request):
        '''退出登录'''
        # 清除用户的session信息
        logout(request)

        # 跳转到首页
        return redirect(reverse('goods:index'))

logout函数清除登录用户的session信息。
添加url

   url(r'^logout$', LogoutView.as_view(), name='logout'), # 注销登录

用户中心_地址页

在这里插入图片描述

修改模板
在这里插入图片描述

在这里插入图片描述

模型管理器类方法封装

model.py

class AddressManager(models.Manager):
    '''地址模型管理器类'''
    # 1.改变原有查询的结果集:all()
    # 2.封装方法:用户操作模型类对应的数据表(增删改查)
    def get_default_address(self, user):
        '''获取用户默认收货地址'''
        # self.model:获取self对象所在的模型类
        try:
            address = self.get(user=user, is_default=True)  # models.Manager
        except self.model.DoesNotExist:
            # 不存在默认收货地址
            address = None 

        return address
        # 调用方法 Address.objects.get_default_address(user)


class Address(BaseModel):
    '''地址模型类'''
    user = models.ForeignKey('User', verbose_name='所属账户')
    receiver = models.CharField(max_length=20, verbose_name='收件人')
    addr = models.CharField(max_length=256, verbose_name='收件地址')
    zip_code = models.CharField(max_length=6, null=True, verbose_name='邮政编码')
    phone = models.CharField(max_length=11, verbose_name='联系电话')
    is_default = models.BooleanField(default=False, verbose_name='是否默认')

    # 自定义一个模型管理器对象
    objects = AddressManager()

    class Meta:
        db_table = 'df_address'
        verbose_name = '地址'
        verbose_name_plural = verbose_name

判断是否存在默认地址导入模型类address
from user.models import User, Address

view.py

# /user/address
class AddressView(LoginRequiredMixin, View):
    '''用户中心-地址页'''
    def get(self, request):
        '''显示'''
        # 获取登录用户对应User对象
        user = request.user

        # 获取用户的默认收货地址
        # try:
        #     address = Address.objects.get(user=user, is_default=True) # models.Manager
        # except Address.DoesNotExist:
        #     # 不存在默认收货地址
        #     address = None
        address = Address.objects.get_default_address(user)

        # 使用模板
        return render(request, 'user_center_site.html', {
    
    'page':'address', 'address':address})

    def post(self, request):
        '''地址的添加'''
        # 接收数据
        receiver = request.POST.get('receiver')
        addr = request.POST.get('addr')
        zip_code = request.POST.get('zip_code')
        phone = request.POST.get('phone')

        # 校验数据
        if not all([receiver, addr, phone]):
            return render(request, 'user_center_site.html', {
    
    'errmsg':'数据不完整'})

        # 校验手机号
        if not re.match(r'^1[3|4|5|7|8][0-9]{9}$', phone):
            return render(request, 'user_center_site.html', {
    
    'errmsg':'手机格式不正确'})

        # 业务处理:地址添加
        # 如果用户已存在默认收货地址,添加的地址不作为默认收货地址,否则作为默认收货地址
        # 获取登录用户对应User对象
        user = request.user

        # try:
        #     address = Address.objects.get(user=user, is_default=True)
        # except Address.DoesNotExist:
        #     # 不存在默认收货地址
        #     address = None

        address = Address.objects.get_default_address(user)

        if address:
            is_default = False
        else:
            is_default = True

        # 添加地址
        Address.objects.create(user=user,
                               receiver=receiver,
                               addr=addr,
                               zip_code=zip_code,
                               phone=phone,
                               is_default=is_default)

        # 返回应答,刷新地址页面
        return redirect(reverse('user:address')) # get请求方式

用户中心_个人信息

修改模板
在这里插入图片描述
在这里插入图片描述

view.py

# /user
class UserInfoView(LoginRequiredMixin, View):
    '''用户中心-信息页'''
    def get(self, request):
        '''显示'''
        # Django会给request对象添加一个属性request.user
        # 如果用户未登录->user是AnonymousUser类的一个实例对象
        # 如果用户登录->user是User类的一个实例对象
        # request.user.is_authenticated()

        # 获取用户的个人信息
        user = request.user
        address = Address.objects.get_default_address(user)

        # 获取用户的历史浏览记录
        # from redis import StrictRedis
        # sr = StrictRedis(host='172.16.179.130', port='6379', db=9)
        con = get_redis_connection('default')

        history_key = 'history_%d'%user.id

        # 获取用户最新浏览的5个商品的id
        sku_ids = con.lrange(history_key, 0, 4) # [2,3,1]

        # 从数据库中查询用户浏览的商品的具体信息
        # goods_li = GoodsSKU.objects.filter(id__in=sku_ids)
        #
        # goods_res = []
        # for a_id in sku_ids:
        #     for goods in goods_li:
        #         if a_id == goods.id:
        #             goods_res.append(goods)

        # 遍历获取用户浏览的商品信息
        goods_li = []
        for id in sku_ids:
            goods = GoodsSKU.objects.get(id=id)
            goods_li.append(goods)

        # 组织上下文
        context = {
    
    'page':'user',
                   'address':address,
                   'goods_li':goods_li}

        # 除了你给模板文件传递的模板变量之外,django框架会把request.user也传给模板文件
        return render(request, 'user_center_info.html', context)

在这里插入图片描述
导入
from goods.models import GoodsSKU

分布式图片服务器FastDFS

什么是FastDFS

FastDFS 是用 c 语言编写的一款开源的分布式文件系统。FastDFS 为互联网量身定制, 充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
FastDFS 架构包括 Tracker serverStorage server。客户端请求 Tracker server 进行文 件上传、下载,通过 Tracker server 调度最终由 Storage server 完成文件上传和下载。
Tracker server 作用是负载均衡和调度,通过 Tracker server 在文件上传时可以根据一些 策略找到 Storage server 提供文件上传服务。可以将 tracker 称为追踪服务器或调度服务器
Storage server 作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上, Storageserver 没有实现自己的文件系统而是利用操作系统 的文件系统来管理文件。可以将 storage 称为存储服务器
在这里插入图片描述
服务端两个角色:

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

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

Django自带的存储系统
在这里插入图片描述
在这里插入图片描述

文件上传流程

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

文件下载流程

在这里插入图片描述

简易FastDFS架构

在这里插入图片描述

FastDFS安装

安装fastdfs依赖包

  1. 解压缩libfastcommon-master.zip
  2. 进入到libfastcommon-master的目录中
  3. 执行 ./make.sh
  4. 执行 sudo ./make.sh install

安装fastdfs

  1. 解压缩fastdfs-master.zip
  2. 进入到 fastdfs-master目录中
  3. 执行 ./make.sh
  4. 执行 sudo ./make.sh install

配置跟踪服务器tracker

1.sudo cp /etc/fdfs/tracker.conf.sample /etc/fdfs/tracker.conf
2. 在/home/python/目录中创建目录 fastdfs/tracker
mkdir –p /home/python/fastdfs/tracker
3. 编辑/etc/fdfs/tracker.conf配置文件 sudo vim /etc/fdfs/tracker.conf
修改
base_path=/home/python/fastdfs/tracker

配置存储服务器storage

  1. sudo cp /etc/fdfs/storage.conf.sample /etc/fdfs/storage.conf
  2. 在/home/python/fastdfs/ 目录中创建目录 storage
    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

启动tracker 和 storage

sudo service fdfs_trackerd start
sudo service fdfs_storaged start

测试是否安装成功

  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
  1. 上传文件测试:
    fdfs_upload_file /etc/fdfs/client.conf 要上传的图片文件
    如果返回类似group1/M00/00/00/rBIK6VcaP0aARXXvAAHrUgHEviQ394.jpg的文件id则说明文件上传成功
    在这里插入图片描述

安装nginx及fastdfs-nginx-module

nginx服务器处理大用户量静态文件效率高,需要使用nginx配合fastdfs进行使用

  1. 解压缩 nginx-1.8.1.tar.gz
  2. 解压缩 fastdfs-nginx-module-master.zip
  3. 进入nginx-1.8.1目录中
  4. 执行
sudo ./configure --prefix=/usr/local/nginx/ --add-module=fastdfs-nginx-module-master 解压后的目录的绝对路径/src

sudo ./make
sudo ./make install
  1. sudo cp fastdfs-nginx-module-master解压后的目录中src下的mod_fastdfs.conf /etc/fdfs/mod_fastdfs.conf
  2. 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
  1. sudo cp 解压缩的fastdfs-master目录conf目录中的http.conf /etc/fdfs/http.conf
  2. sudo cp 解压缩的fastdfs-master目录conf目录中的mime.types /etc/fdfs/mime.types
    9.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;
            }
        }
  1. 启动nginx
    sudo /usr/local/nginx/sbin/nginx
    停止
    sudo /usr/local/nginx/sbin/nginx -s stop

使用python客户端上传测试

  1. workon django_py3
  2. 进入fdfs_client-py-master.zip所在目录
  3. pip install fdfs_client-py-master.zip
>>> from fdfs_client.client import Fdfs_client
>>> client = Fdfs_client('/etc/fdfs/client.conf')
>>> ret = client.upload_by_filename('test')
>>> 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'}

参考文档 https://github.com/jefforeilly/fdfs_client-py

项目上传图片和使用图片流程

在这里插入图片描述

Django二次开发对接FastDFS

参考文档:
https://doc.codingdict.com/django/ref/files/storage.html#module-django.core.files.storage
https://doc.codingdict.com/django/howto/custom-file-storage.html

自定义文件存储类

新建fds
修改conf文件
在这里插入图片描述
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://172.16.179.131:8888/'

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

        return filename

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

    def url(self, name):
        '''返回访问文件的url路径'''
        return self.base_url+name

图片如何调用
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_27251475/article/details/120653639
今日推荐