Django3+Vue Million商城项目的总结

项目说明

概述: Million商城是一个基于django3+vue前后端的网页电子商城项目
主要技术:Django3+Vue+MySQL+Redis+Celery+FastDFS+Docker+Elasticsearch+Crontab+jwt+git
主要负责:后端逻辑业务的实现
功能模块:
验证: 图形验证、短信验证
用户: 注册、登录、用户中心(基本信息、邮箱激活、收货地址、我的订单、修改密码)
第三方登录: QQ登录
首页广告: 首页广告
商品: 商品列表、商品搜索、商品详情、商品浏览记录
购物车: 购物车管理、购物车合并
订单 :确认订单、提交订单、订单商品评价
支付 :支付宝支付
MIS系统: 数据统计、用户管理、权限管理、商品管理、订单管理

主要环境搭建

1、安装Ubuntu20.04
2、python3.8
3、mysql8.0
4、django3.2
5、创建一个虚拟环境

主要技术实现

django 的配置文件

settings.py

"""
Django settings for MeiDuoMall project.

Generated by 'django-admin startproject' using Django 3.2.9.

For more information on this file, see
https://docs.djangoproject.com/en/3.2/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.2/ref/settings/
"""
import os
from pathlib import Path

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-@^-w9%jg)^mmc=a!8d^67gukvdshk#lkrt-q$!9^ah#0x0fzoa'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

# 配置浏览的网址及ip地址
ALLOWED_HOSTS = ['www.meiduo.site', '127.0.0.1']

# 指定本项目用户模型类
AUTH_USER_MODEL = 'users.User'

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',  # 允许CORS跨域资源访问
    'apps.users',
    'apps.verifications',
    'apps.oauth',
    'apps.areas',
    'apps.contents',
    'apps.goods',
    'apps.carts',
    'apps.orders',
    'apps.payment',
    'haystack',  # 全文检索
    'django_crontab',  # 定时任务
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',  # 注释掉防止csrf
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'corsheaders.middleware.CorsMiddleware',  # 允许CORS跨域访问中间件
]

ROOT_URLCONF = 'MeiDuoMall.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'MeiDuoMall.wsgi.application'

# Database
# https://docs.djangoproject.com/en/3.2/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'meiduo_mall',
        'USER': 'root',
        'PASSWORD': '20000716',
        'HOST': 'localhost',
        'PORT': 3306
    }
}

# Password validation
# https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# Internationalization
# https://docs.djangoproject.com/en/3.2/topics/i18n/

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'

# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

# django-redis配置
CACHES = {
    "default": {  # 默认, 预留
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/0",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    },
    "session": {  # 调用于session存储
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/1",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    },
    "code": {  # 验证码
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/2",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
            }
    },
    "history": {  # 用户浏览记录
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/3",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    },
    "carts": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379/4",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    },
}

# 配置session存储
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALTAS = "session"

# 配置日志文件
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,  # 是否禁用已经存在的日志器
    'formatters': {  # 日志信息显示的格式
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
        },
    },
    'filters': {  # 对日志进行过滤
        'require_debug_true': {  # django在debug模式下才输出日志
            '()': 'django.utils.log.RequireDebugTrue',
        },
    },
    'handlers': {  # 日志处理方法
        'console': {  # 向终端中输出日志
            'level': 'INFO',
            'filters': ['require_debug_true'],
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        'file': {  # 向文件中输出日志
            'level': 'INFO',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(BASE_DIR, 'logs/meiduo.log'),  # 日志文件的位置
            'maxBytes': 300 * 1024 * 1024,
            'backupCount': 10,
            'formatter': 'verbose'
        },
    },
    'loggers': {  # 日志器
        'django': {  # 定义了一个名为django的日志器
            'handlers': ['console', 'file'],  # 可以同时向终端与文件中输出日志
            'propagate': True,  # 是否继续传递日志信息
            'level': 'INFO',  # 日志器接收的最低日志级别
        },
    }
}

# CORS
CORS_ORIGIN_WHITELIST = (
    'http://127.0.0.1:8080',
    'http://localhost:8080',
    'http://www.meiduo.site:8080',
    'http://www.meiduo.site:8000'
)
CORS_ALLOW_CREDENTIALS = True  # 允许携带cookie

# QQ登录参数
# 我们申请的 客户端id
QQ_CLIENT_ID = '101474184'
# 我们申请的 客户端秘钥
QQ_CLIENT_SECRET = 'c6ce949e04e12ecc909ae6a8b09b637c'
# 我们申请时添加的: 登录成功后回调的路径
QQ_REDIRECT_URI = 'http://www.meiduo.site:8080/oauth_callback.html'

# 配置邮箱服务器
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
# 发送邮件的邮箱
EMAIL_HOST_USER = 'xcl20001109@163.com'
# 在邮箱中设置的客户端授权密码
# 授权码:JAKIIADAWRQPRODG
EMAIL_HOST_PASSWORD = 'JAKIIADAWRQPRODG'
# 收件人看到的发件人
EMAIL_FROM = '美多商城<xcl20001109@163.com>'
# 邮箱验证链接
EMAIL_VERIFY_URL = 'http://www.meiduo.site:8080/success_verify_email.html'

# 指定自定义的Django文件存储类
DEFAULT_FILE_STORAGE = 'utils.fastdfs.storage.FastDFSStorage'

# FastDFS相关参数
# FDFS_BASE_URL = 'http://192.168.103.158:8888/'
FDFS_BASE_URL = 'http://192.168.42.130:8888/'

# Haystack
# Haystack
HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
        'URL': 'http://192.168.42.130:9200/',  # Elasticsearch服务器ip地址,端口号固定为9200
        'INDEX_NAME': 'meiduo_mall',  # Elasticsearch建立的索引库的名称
    },
}

# 当添加、修改、删除数据时,自动生成索引
# HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

# 设置搜索后每页展示的数据量
HAYSTACK_SEARCH_RESULTS_PER_PAGE = 5

# 定时任务
CRONJOBS = [
    # 每1分钟生成一次首页静态文件
    ('*/1 * * * *', 'apps.contents.crons.generate_static_index_html', '>> ' + os.path.join(BASE_DIR, 'logs/crontab.log'))
]

# 用于解决在定时任务中,如果出现非英文字符,会出现字符异常错误
CRONTAB_COMMAND_PREFIX = 'LANG_ALL=zh_cn.UTF-8'


# 支付宝SDK参数配置
ALIPAY_APPID = '2021000121646967'
ALIPAY_DEBUG = True
ALIPAY_URL = 'https://openapi.alipaydev.com/gateway.do'
ALIPAY_RETURN_URL = 'http://www.meiduo.site:8080/pay_success.html'
APP_PRIVATE_KEY_PATH = os.path.join(BASE_DIR, 'apps/payment/keys/app_private_key.pem')
ALIPAY_PUBLIC_KEY_PATH = os.path.join(BASE_DIR, 'apps/payment/keys/alipay_public_key.pem')


celery的使用(异步发送短信验证码和邮箱验证链接)

Celery介绍:

一个简单、灵活且可靠、处理大量消息的分布式系统,可以在一台或者多台机器上运行。
Celery是一个功能完备即插即用的任务队列
单个 Celery 进程每分钟可处理数以百万计的任务。
通过消息进行通信,使用消息队列(broker)在客户端和消费者之间进行协调。

安装Celery:pip install -U Celery

Celery官方文档

主要文件main.py

import os
import sys
# 用于解决终端报错:from libs.yuntongxun.yuntongxun.sms import CCP
# 并且这句话不能加在sms中的tasks.py文件里,否则发送短信时会直接调用yuntongxun里的sms里的send_template_sms方法
sys.path.append('/home/mm0716/Desktop/python/meiduomall/meiduo_mall/MeiDuoMall')
import logging
from celery import Celery

# 配置celery在django中的运行环境
os.environ.setdefault('DJANGO_SETTING_MODULE', 'MeiDuoMall.settings')
# 创建celery实例对象
celery_app = Celery('celery_tasks')
# 添加celery配置
celery_app.config_from_object('celery_tasks.config')
# 自动注册任务
celery_app.autodiscover_tasks(['celery_tasks.sms', 'celery_tasks.email'])

配置文件config.py

# 将任务存储在Redis3号库
broker_url = 'redis://127.0.0.1:6379/3'

使用方法:
1、在项目根目录下创建一个celery_tasks文件夹,用于存放main.py, config.py文件,以及每个要执行异步任务的文件夹
2、在celery_tasks下创建任务文件夹,每个任务文件夹下创建一个tasks.py文件用于书写要执行的任务
3、在main.py里注册任务
4、在celery_tasks文件夹所在的文件夹开启celery服务:命令行输入命令:celery -A celery_tasks.main worker -l info

容联云通讯短信平台

用于发送短信验证码

查看官方文档实现接入
容联云通讯网址: https://www.yuntongxun.com/

QQ登录

官方文档实现接入
http://wiki.connect.qq.com/%E6%88%90%E4%B8%BA%E5%BC%80%E5%8F%91%E8%80%85

jwt实现加密解密验证实现数据的安全性

用于qq登录的回调验证和邮箱激活链接的验证
导入authlib包:pip install authlib
项目中实现jwt的文件
token.py

from authlib.jose import jwt, JoseError

from apps.users.models import User
from MeiDuoMall import settings


# 用于生成加密后的token
def generate_access_token(openid):
    """
    openid: 用户的签名
    return: access_token
    """
    # 使用authlib加密的算法
    header = {'alg': 'HS256'}
    # 用于加密的salt
    key = settings.SECRET_KEY
    # 需要加密的对象
    data = {'openid': openid}
    access_token = jwt.encode(header=header, key=key, payload=data)
    return access_token.decode()


# 用于检查token是否正确
def check_access_token(access_token):
    """用于验证token是否正确"""
    # salt与加密时用的一致
    key = settings.SECRET_KEY
    try:
        # 解密验证
        data = jwt.decode(access_token, key)
        print(data)
    except JoseError:
        # 解密失败即token不正确
        return None
    # 验证正确返回openid
    return data.get('openid')


# 生成邮箱验证链接
def generate_verify_email_url(user):
    """
    user: 当前登录用户
    return verify_url
    """
    # 用于生成token的算法
    header = {'alg': 'HS256'}
    # salt
    key = settings.SECRET_KEY
    # 用于加密的数据
    data = {'user_id': user.id, 'email': user.email}
    token = jwt.encode(header=header, key=key, payload=data)
    verify_url = settings.EMAIL_VERIFY_URL + '?token=' + token.decode()
    return verify_url


# 校验邮箱验证链接里的token
def check_verify_email_url(token):
    """
    token: 加密后的数据
    return user
    """
    # salt
    key = settings.SECRET_KEY
    try:
        # 解密token
        data = jwt.decode(token, key)
    except JoseError:
        # token不正确
        return None
    else:
        user_id = data.get('user_id')
        email = data.get('email')
        try:
            # 获取用户对象
            user = User.objects.get(id=user_id, email=email)
        except User.DoesNotExist:
            # 用户不存在
            return None
        return user

FastDFS+Docker实现图片数据的展示

FastDFS

  1. 介绍:

用c语言编写的一款开源的轻量级分布式文件系统。
功能包括:文件存储、文件访问(文件上传、文件下载)、文件同步等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。
为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标。
可以帮助我们搭建一套高性能的文件服务器集群,并提供文件上传、下载等服务。
在这里插入图片描述
FastDFS架构 包括Client、Tracker server和Storage server。
Client请求Tracker进行文件上传、下载,Tracker再调度Storage完成文件上传和下载。
Client: 客户端,业务请求的发起方,通过专有接口,使用TCP/IP协议与Tracker或Storage进行数据交互。FastDFS提供了upload、download、delete等接口供客户端使用。
Tracker server:跟踪服务器,主要做调度工作,起负载均衡的作用。在内存中记录集群中所有存储组和存储服务器的状态信息,是客户端和数据服务器交互的枢纽。
Storage server:存储服务器(存储节点或数据服务器),文件和文件属性都保存到存储服务器上。Storage server直接利用OS的文件系统调用管理文件。
Storage群中的横向可以扩容,纵向可以备份。

  1. FastDFS上传和下载流程
    在这里插入图片描述
    在这里插入图片描述

  2. FastDFS文件索引

    FastDFS上传和下载流程可以看出都涉及到一个数据叫文件索引(file_id)。
    文件索引(file_id)是客户端上传文件后Storage返回给客户端的一个字符串,是以后访问该文件的索引信息。
    文件索引(file_id)信息包括:组名、虚拟磁盘路径、数据两级目录、文件名等信息。
    组名:文件上传后所在的 Storage 组名称。
    虚拟磁盘路径:Storage 配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0则是M00,如果配置了store_path1则是M01,以此类推。
    数据两级目录:Storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
    文件名:由存储服务器根据特定信息生成,文件名包含:源存储服务器IP地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

Docker

概述:Docker就是一个容器,能够提供一个运行环境,不用自己去搭建许多技术的应用环境,可以直接从docker中拉取想要的环境,来帮助自己完成项目开发。

  1. Docker介绍

Docker中文社区文档
Docker 是一个开源的软件部署解决方案。
Docker 也是轻量级的应用容器框架。
Docker 可以打包、发布、运行任何的应用。
Docker 就像一个盒子,里面可以装很多物件,如果需要某些物件,可以直接将该盒子拿走,而不需要从该盒子中一件一件的取。
Docker 是一个客户端-服务端(C/S)架构程序。
客户端只需要向服务端发出请求,服务端处理完请求后会返回结果。
Docker 包括三个基本概念:

  1. 镜像(Image)

Docker的镜像概念类似于虚拟机里的镜像,是一个只读的模板,一个独立的文件系统,包括运行容器所需的数据,可以用来创建新的容器。
例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了MySQL或用户需要的其它应用程序。

  1. 容器(Container)

Docker容器是由Docker镜像创建的运行实例,类似VM虚拟机,支持启动,停止,删除等。
每个容器间是相互隔离的,容器中会运行特定的应用,包含特定应用的代码及所需的依赖文件。
仓库(Repository)
Docker的仓库功能类似于Github,是用于托管镜像的

  1. Docker的操作指令

    安装完成Docker后,默认已经启动了docker服务。

    • 启动dockersudo service docker start
    • 重启dockersudo service docker restart
    • 停止dockersudo service docker stop

    Docker镜像操作
    1. 镜像列表

     $ sudo docker image ls
     
     
     * REPOSITORY:镜像所在的仓库名称 
     * TAG:镜像标签 
     * IMAGEID:镜像ID 
     * CREATED:镜像的创建日期(不是获取该镜像的日期) 
     * SIZE:镜像大小
     2.从仓库拉取镜像
     
     # 官方镜像
     
     $ sudo docker image pull 镜像名称 或者 sudo docker image pull library/镜像名称
     $ sudo docker image pull ubuntu 或者 sudo docker image pull library/ubuntu
     $ sudo docker image pull ubuntu:16.04
     或者 sudo docker image pull library/ubuntu:16.04
     # 个人镜像
     
     $ sudo docker image pull 仓库名称/镜像名称
     $ sudo docker image pull itcast/fastdfs
     
     
     3.删除镜像
     
     $ sudo docker image rm 镜像名或镜像ID
     $ sudo docker image rm hello-world
     $ sudo docker image rm fce289e99eb9
    

    Docker容器操作

    1. 容器列表

       # 查看正在运行的容器
       $ sudo docker container ls
       # 查看所有的容器
       $ sudo docker container ls --all		
      
    2. 创建容器

       $ sudo docker run [option] 镜像名 [向启动容器中传入的命令]
       常用可选参数说明:
       * -i 表示以《交互模式》运行容器。
       * -t 表示容器启动后会进入其命令行。加入这两个参数后,容器创建就能登录进去。即分配一个伪终端。
       * --name 为创建的容器命名。
       * -v 表示目录映射关系,即宿主机目录:容器中目录。注意:最好做目录映射,在宿主机上做修改,然后共享到容器上。 
       * -d 会创建一个守护式容器在后台运行(这样创建容器后不会自动登录容器)。 
       * -p 表示端口映射,即宿主机端口:容器中端口。
       * --network=host 表示将主机的网络环境映射到容器中,使容器的网络与主机相同。
      
    3. 交互式容器

       $ sudo docker run -it --name=ubuntu1 ubuntu /bin/bash
       
       
       在容器中可以随意执行linux命令,就是一个ubuntu的环境。
       当执行 exit 命令退出时,该容器随之停止。
      
    4. 守护式容器

       # 开启守护式容器
       
       $ sudo docker run -dit --name=ubuntu2 ubuntu
       
       
       # 进入到容器内部交互环境
       
       $ sudo docker exec -it 容器名或容器id 进入后执行的第一个命令
       $ sudo docker exec -it ubuntu2 /bin/bash
       
       
       如果对于一个需要长期运行的容器来说,我们可以创建一个守护式容器。
       在容器内部执行 exit 命令退出时,该容器也随之停止。
      
    5. 停止和启动容器

       # 停止容器
       
       $ sudo docker container stop 容器名或容器id
       
       # kill掉容器
       
       $ sudo docker container 
       kill 容器名或容器id
       
       # 启动容器
       
       $ sudo docker container start 容器名或容器id
      
    6. 删除容器

       正在运行的容器无法直接删除。要先停止再删除
       $ sudo docker container rm 容器名或容器id
      
    7. 容器制作成镜像

       为保证已经配置完成的环境可以重复利用,我们可以将容器制作成镜像。
       # 将容器制作成镜像
       
       $ sudo docker commit 容器名 镜像名
       
       
       # 镜像打包备份
       
       $ sudo docker save -o 保存的文件名 镜像名
       
       
       # 镜像解压
       
       $ sudo docker load -i 文件路径/备份文件
      

Docker安装运行FastDFS

  1. 获取FastDFS镜像

     # 从仓库拉取镜像
     $ sudo docker image pull delron/fastdfs
    
  2. 开启tracker容器

     我们将 tracker 运行目录映射到宿主机的/var/fdfs/tracker目录中。
     $ sudo docker run -dit --name tracker --network=host -v /var/fdfs/tracker:/var/fdfs delron/fastdfs tracker
    
  3. 开启storage容器

     TRACKER_SERVER=Tracker的ip地址:22122(Tracker的ip地址不要使用127.0.0.1)
     我们将 storage 运行目录映射到宿主机的/var/fdfs/storage目录中。
     $ sudo docker run -dti --name storage --network=host -e TRACKER_SERVER=192.168.42.130:22122 -v /var/fdfs/storage:/var/fdfs delron/fastdfs storage
    
  4. 查看宿主机映射路径
    在这里插入图片描述

     注意:如果无法重启storage容器,可以删除/var/fdfs/storage/data目录下的fdfs_storaged.pid文件,然后重新运行storage。
    
  5. 安装FastDFS客户端扩展

     安装准备好的fdfs_client-py-master.zip到虚拟环境中
     $ pip install fdfs_client-py-master.zip
     $ pip install mutagen
     $ pip install requests	
    
  6. 准备FastDFS客户端扩展的配置文件

    utils.fastdfs.client.conf

    	# connect timeout in seconds
    # default value is 30s
    connect_timeout=30
    
    # network timeout in seconds
    # default value is 30s
    network_timeout=120
    
    # the base path to store log files
    base_path=/home/mm0716/Desktop/fastdfs_log/
    
    # tracker_server can ocur more than once, and tracker_server format is
    #  "host:port", host can be hostname or ip address
    # 本机ip
    tracker_server=192.168.42.130:22122
    
    #standard log level as syslog, case insensitive, value list:
    ### emerg for emergency
    ### alert
    ### crit for critical
    ### error
    ### warn for warning
    ### notice
    ### info
    ### debug
    log_level=info
    
    # if use connection pool
    # default value is false
    # since V4.05
    use_connection_pool = false
    
    # connections whose the idle time exceeds this time will be closed
    # unit: second
    # default value is 3600
    # since V4.05
    connection_pool_max_idle_time = 3600
    
    # if load FastDFS parameters from tracker server
    # since V4.05
    # default value is false
    load_fdfs_parameters_from_tracker=false
    
    # if use storage ID instead of IP address
    # same as tracker.conf
    # valid only when load_fdfs_parameters_from_tracker is false
    # default value is false
    # since V4.05
    use_storage_id = false
    
    # specify storage ids filename, can use relative or absolute path
    # same as tracker.conf
    # valid only when load_fdfs_parameters_from_tracker is false
    # since V4.05
    storage_ids_filename = storage_ids.conf
    
    
    #HTTP settings
    http.tracker_server_port=80
    
    #use "#include" directive to include HTTP other settiongs
    ##include http.conf
    
    
     base_path=FastDFS客户端存放日志文件的目录
     tracker_server=运行Tracker服务的机器ip:22122
    

    utils.fastdfs.storage.py

    """
    重写Django文件存储类url()方法
    自定义的存储类,用于修改查看storage里的文件地址
    不进行重写的话前端会进行拼接以至于访问图片的地址出现问题
    """
    
    from django.core.files.storage import Storage
    from MeiDuoMall import settings
    
    
    class FastDFSStorage(Storage):
    
        # 自定义必须写这两个
        def _open(self, name, mode='rb'):
            pass
    
        def _save(self, name, content):
            pass
    
        def url(self, name):
            """
            返回name所指文件的绝对URL
            :param name: 要读取文件的引用:group1/M00/00/00/wKhnnlxw_gmAcoWmAAEXU5wmjPs35.jpeg
            :return: http://192.168.42.130:8888/group1/M00/00/00/wKhnnlxw_gmAcoWmAAEXU5wmjPs35.jpeg
            """
            return settings.FDFS_BASE_URL + name
    
    

    重写完之后在settings里设置

    # 指定自定义的Django文件存储类
    DEFAULT_FILE_STORAGE = 'utils.fastdfs.storage.FastDFSStorage'
    
  7. FastDFS客户端实现文件存储

     # 使用 shell 进入 Python交互环境
     $ python manage.py shell
     上传文件需要先创建fdfs_client.client.Fdfs_client的对象,并指明配置文件,如
     
     from fdfs_client.client import Fdfs_client
     client = Fdfs_client('utils/fastdfs/client.conf')
     通过创建的客户端对象执行上传文件的方法
     
     client.upload_by_filename(文件名)
     或
     client.upload_by_buffer(文件bytes数据)
     如:
     
     >>> from fdfs_client.client import Fdfs_client
     >>> client=Fdfs_client('utils/fastdfs/client.conf')
     >>> client.upload_by_filename('/home/python/Desktop/images/0.jpg')
     getting connection
     <fdfs_client.connection.Connection object at 0x7f25174eb940>
     <fdfs_client.fdfs_protol.Tracker_header object at 0x7f25174eb908>
     {'Remote file_id': 'group1/M00/00/00/wKjlhFsTgJ2AJvG_AAAyZgOTZN0850.jpg', 'Uploaded size': '12.00KB',
      'Local file name': '/home/python/Desktop/images/0.jpg', 'Storage IP': '192.168.229.132',
       'Group name': 'group1', 'Status': 'Upload successed.'}
    

    ‘Group name’: ‘Storage组名’,
    ‘Remote file_id’: ‘文件索引,可用于下载’,
    ‘Status’: ‘文件上传结果反馈’,
    ‘Local file name’: ‘上传文件全路径’,
    ‘Uploaded size’: ‘文件大小’,
    ‘Storage IP’: ‘Storage地址’

  8. 浏览器下载并渲染图片
    思考:如何才能找到在Storage中存储的图片?

     协议:
     http
     IP地址:192.168.42.130
     Nginx服务器的IP地址。
     因为 FastDFS 擅长存储静态文件,但是不擅长提供静态文件的下载服务,所以我们一般会将 Nginx 服务器绑定到 Storage ,提升下载性能。
     端口:8888
     Nginx服务器的端口。
     路径:group1/M00/00/00/wKhnnlxw_gmAcoWmAAEXU5wmjPs35.jpeg
     文件在Storage上的文件索引。
     完整图片下载地址
     http://192.168.42.130:8888/group1/M00/00/00/wKhnnlxw_gmAcoWmAAEXU5wmjPs35.jpeg
    

git推送项目到gitee上

完成一个模块退出项目的时候要及时提交并推送,以防虚拟机出现问题,项目整体丢失

git的操作

uwsgi部署

  1. 安装uwsgi包

     Django的程序通常使用uwsgi服务器来运行。
     $ pip install uwsgi
    
  2. 准备uwsgi服务器配置文件

    新建MeiDuoMall.uwsgi.ini配置文件

    [uwsgi]
    # 使用Nginx连接时使用,Django程序所在服务器地址
    #socket=172.16.21.25:8001
    # 直接做web服务器使用,Django程序所在服务器地址
    http=127.0.0.1:8000
    # 项目目录
    chdir=/home/mm0716/Desktop/python/meiduomall/meiduo_mall/MeiDuoMall
    # 项目中wsgi.py文件的目录,相对于项目目录
    wsgi-file=MeiDuoMall/wsgi.py
    # 进程数
    processes=4
    # 线程数
    threads=2
    # uwsgi服务器的角色
    master=True
    # 存放进程编号的文件
    pidfile=uwsgi.pid
    # 日志文件
    daemonize=uwsgi.log
    # 指定依赖的虚拟环境(进入到虚拟环境终端输入which python可查看,复制到虚拟环境名之前即可)
    virtualenv=/home/mm0716/.virtualenvs/django_worken
    
  3. 管理uwsgi服务器

     # 启动
     $ uwsgi --ini uwsgi.ini
     # 关闭
     $ uwsgi --stop uwsgi.pid
    

项目成品

运行项目:
1、命令:sudo workon django_workon进入到虚拟环境
2、终端命令:sudo redis-server /etc/redis/redis.conf, 开启redis数据
3、去到静态文件目录下:python3 -m http.server 8080, 开启前端服务
4、命令:
实现图片文件的获取:
sudo docker container start tracker
sudo docker container start storage
实现搜索功能
sudo docker container start Elasticsearch
5、在项目目录下:uwsgi --ini uwsgi.ini 启动后端服务

1、首页展示

2、注册
在这里插入图片描述

在这里插入图片描述

3、登录
在这里插入图片描述

4、QQ登录
在这里插入图片描述

5、商品列表页
在这里插入图片描述

6、商品详情页
在这里插入图片描述

7、用户中心
在这里插入图片描述

8、修改地址
在这里插入图片描述

9、修改密码
在这里插入图片描述

10、订单展示
在这里插入图片描述

11、购物车
在这里插入图片描述

12、结算页面
在这里插入图片描述

13、支付页面

在这里插入图片描述

遇到的问题

1、有时候打开虚拟机,在pycharm完成项目中的一小部分后,按ctrl+k进行提交时会出现Error files的问题

error: object file .git/objects/31/65329bb680e30595f242b7c4d8406ca63eeab0 is empty

原因:可能是退出pycharm的时候,没有停止项目的运行直接退出,导致git文件出错
解决方法:https://blog.csdn.net/weixin_34055910/article/details/89065892

这个解决后可能会随之出现的问题:
error: invalid object 100644 fdc91c997bd43dddd3eb84094e79b5a681453475 for ‘xxxx’
解决方法:https://blog.csdn.net/qq_36898054/article/details/121563683

2、在创建统计商品访问次数的时候创建模型添加外键报错:
Referencing column ‘xx’ and referenced column ‘xx’ in foreign key constraint ‘xxx’ are incompatible.

原因:自动添加的外键的类型是bigint而对应的外键类型是int,原因是因为当前Django升级到了3.2以上,所以每次使用migrate生成数据库的时候,主键id自动会变成BigInt类型
解决方法: 修改每个表的主键的类型为int(11)

在每个app的app.py文件里

class GoodsConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'apps.goods'

解决方法:修改BigAutoField 为AutoField

3、俩个问题:
一个是终端运行celery报错没有libs包的问题,另一个是使用pycharm运行django项目进行debug调试
问题及解决方法:https://blog.csdn.net/COOL66BOY/article/details/126216616?spm=1001.2014.3001.5502

4、在实现MySQL的主从读写分离的优化的时候,以Ubuntu自身的mysql8.0.30做主服务器,docker里的mysql8.0.27做从服务器
在用命令:sudo docker run --name mysql-slave -e MYSQL_ROOT_PASSWORD=mysql -d --network=host -v /home/mm0716/mysql_slave/data:/var/lib/mysql -v /home/mm0716/mysql_slave/mysql.conf.d:/etc/mysql/mysql.conf.d mysql创建容器执行mysql从服务器时,报错3306端口已被使用,而映射的配置文件里已经端口改为8306了,因此导致运行起来后,没一会儿容器就自动停了

用命令:sudo docker run --name mysql-slave -e MYSQL_ROOT_PASSWORD=mysql -d -p 8306:8306 -v /home/mm0716/mysql_slave/data:/var/lib/mysql -v /home/mm0716/mysql_slave/mysql.conf.d:/etc/mysql/mysql.conf.d mysql创建后
必须修改交互模式下mysql的my.cnf文件,添加端口才能在Ubuntu终端用命令:mysql -uroot -p20000716 -h 127.0.0.1 --port=8306打开mysql,否则报错。再打开后进行主从配置,每个步骤都没错的情况下,密码输入也正确,创建的slave运行起来后报错:
在这里插入图片描述
在这里插入图片描述
目前在寻找一个解决方法,因此MySQL的读写分离未实现

5、Ubuntu内存不够的问题,内存不够的时候如果项目还需要内存,要及时扩容分区内存,不然可能导致虚拟机黑屏,程序无法正常运行的问题
解决方法:先关闭虚拟机,然后编辑设置扩展硬盘容量之后按照https://blog.csdn.net/thy0000/article/details/122882955对应的步骤完成即可

总结

在完成这个项目的过程中,出现了大大小小的许多问题,在项目完成70%的时候虚拟机也坏过一次重装过,然后项目重新又开始做了一遍,虽然在项目快完成的时候,虚拟机坏了让人很烦躁,但重新再做一遍前面的项目内容后,我对项目中的技术又加强了记忆,也算是一种收获。从这次项目中我得到了一下几点收获:
1、掌握了Django框架、git操作项目,Redis数据库,Celery任务异步发送的使用
2、熟悉了FastDFS文件分布式存储,Docker,Elasticsearch全文检索, Crontab定时任务的基本使用
3、了解了vue的使用,以及前后端axios数据的传输和RESTful设计风格;了解了uwsgi部署Django项目
4、对数据库的增删改查SQL语句更加熟练
5、了解到了电子商城的后端逻辑业务,以及数据库,数据表的设计
6、分析问题和解决问题的能力,能够用debug调试工具寻找问题的根源所在
7、学会去查阅各种开发文档

  • 4
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值