部署
当Django运行在生产模式时,将不再提供静态文件的支持,需要将静态文件交给静态文件服务器。
我们先收集所有静态文件。项目中的静态文件除了我们使用的front_end_pc中之外,django本身还有自己的静态文件,如果rest_framework、xadmin、admin、ckeditor等。我们需要收集这些静态文件,集中一起放到静态文件服务器中。
我们要将收集的静态文件放到front_end_pc目录下的static目录中,所以先创建目录static。
Django提供了收集静态文件的方法。先在配置文件中配置收集之后存放的目录
STATIC_ROOT = os.path.join(os.path.dirname(os.path.dirname(BASE_DIR)), 'front_end_pc/static')
然后执行收集命令
python manage.py collectstatic
我们使用Nginx服务器作为静态文件服务器
2.Nginx服务器安装:
如果本机安装了nginx,卸载nginx
apt-get --purge autoremove nginx
检查本机是否还有nginx程序在后台运行,如果有直接kill掉
ps -ef | grep nginx
默认版本安装
方便简单,很多依赖都自动给安装好了,一个命令即可 在root 用户下
apt-get update # 更新包
如果在更新的时候下面没有公钥的的报错:
# 由于没有公钥,无法验证下列签名: NO_PUBKEY 9165938D90FDDD2E
则运行 下面的命令
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys + NO_PUBKEY后面的公钥
比如:
#sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 9165938D90FDDD2E
最后重新 apt-get update
# 安装Nginx
apt-get install nginx
文件介绍
/usr/sbin/nginx:主程序,启动文件
/etc/nginx:存放配置文件
/var/www/html:存放项目目录
/var/log/nginx:存放日志
一般自动安装配置文件目录和主程序目录不变,因为版本原因,其它目录可能会变,但是都可以从配置文件里ngxin.conf里找到对应的位置。
在浏览器(Ubuntu里面的)里面访问127.0.0.1:80 显示Nginx安装成功就可以了
打开Nginx的配置文件
进入root用户:
sudo su
pythonvip
sudo vim /etc/nginx/nginx.conf
在server部分中配置(这里可暂时不去写,最后下面有完整的参照)
# 前端服务器配置
server {
listen 8000; # 服务的端口号
server_name 127.0.0.1; # 服务的id
location / {
root /home/python/Desktop/front_end_pc; # 前端服务路径
index index.html index.htm;
}
# 余下省略
}
重启Nginx服务器
sudo /usr/sbin/nginx -s reload 重启Nginx
首次启动nginx服务器
sudo /usr/local/nginx/sbin/nginx
停止nginx服务器
sudo /usr/local/nginx/sbin/nginx -s stop
在项目中复制开发配置文件dev.py 到生产配置prod.py
修改配置文件prod.py中
DEBUG = False
ALLOWED_HOSTS = [..., 'http://127.0.0.1:8000','http://127.0.0.1:8001'] # 添加
CORS_ORIGIN_WHITELIST = (
.....
#添加
'http://127.0.0.1:8000',
'http://127.0.0.1:8001',
'http://127.0.0.1:8002',
)
修改wsgi.py文件
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "meiduo_mall.settings.prod")
django的程序通常使用uwsgi服务器来运行
3安装uwsgi
在当前项目的虚拟环境中安装:
pip install uwsgi
在项目目录/好课_mall 下创建uwsgi配置文件 uwsgi.ini 该文件与manage.py同级目录
[uwsgi]
#使用nginx连接时使用,Django程序所在服务器地址
socket=192.168.1.107:8002 # 该 ip可以是服务器的地址 这里我们用Ubuntu的地址和ip
#直接做web服务器使用,Django程序所在服务器地址
#http=10.211.55.2:8001 # 这里是用做uwsgi与Django通信是否注册的时候使用的,一般在Nginx访问后端后端的接口报错的时候可以使用,一般很少用
#项目目录
chdir=/home/pyvip/hualong/haoke_mall
#项目中wsgi.py文件的目录,相对于项目目录
wsgi-file=haoke_mall/wsgi.py
# 进程数
processes=4
# 线程数
threads=2
# uwsgi服务器的角色
master=True
# 存放进程编号的文件
pidfile=uwsgi.pid
# 日志文件,因为uwsgi可以脱离终端在后台运行,日志看不见。我们以前的runserver是依赖终端的
# 方便查看报错信息的
daemonize=uwsgi.log
# 指定依赖的虚拟环境
virtualenv=/home/pyvip/.virtualenvs/hualong
# 最大运行内存
buffer-size = 65536
启动uwsgi服务器:在 uwsgi.ini 目录下
uwsgi --ini uwsgi.ini
注意如果想要停止服务器,除了可以使用kill命令之外,还可以通过
uwsgi --stop uwsgi.pid
注意:
uwsgi --ini uwsgi.ini 启动后会生成 uwsgi.log 这个里面一定要记得去看看 ,启动是否成功,端口号是否被占用等情况 比如: 192.168.1.107:8002 已存在 则是8002被占用了
可以用命令杀掉这个端口在重启:
比如: 记得执行2次
sudo fuser -k 8002/tcp
修改Nginx配置文件,让Nginx接收到请求后转发给uwsgi服务器
user root;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
http {
# 使css文件正常加载
include mime.types;
default_type application/octet-stream;
upstream haoke111 {
server 192.168.1.101:8002;
}
# 后端的ip配置
server {
listen 8001;
server_name 127.0.0.1;
charset utf-8;
location / {
include uwsgi_params ;
uwsgi_pass haoke111;
}
location /static {
alias /home/pyvip/hualong/front_end_pc/static;
}
}
# 前端的服务配置
server {
listen 8000;
server_name 127.0.0.1;
#charset koi8-r;
#access_log logs/host.access.log main;
location /admin {
include uwsgi_params;
uwsgi_pass haoke111;
}
location /ckeditor {
include uwsgi_params;
uwsgi_pass haoke111;
}
location / {
root /home/pyvip/hualong/front_end_pc;
index index.html index.htm;
}
# 使css文件正常加载
location ~.*(js|css|png|gif|jpg|mp3|ogg)$ {
root /home/pyvip/hualong/front_end_pc/;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
events {
worker_connections 1024; #nginx的最大并发访问量
use epoll; #异步IO
}
重启nginx
sudo /usr/sbin/nginx -s reload 重启Nginx
如果出现 :nginx: [error] open() “/run/nginx.pid” failed (2: No such file or directory)
则执行:
sudo nginx -c /etc/nginx/nginx.conf
然后再重启
sudo /usr/sbin/nginx -s reload
prod.py
"""
Django settings for haoke_mall project.
Generated by 'django-admin startproject' using Django 3.1.10.
For more information on this file, see
https://docs.djangoproject.com/en/3.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.1/ref/settings/
"""
import datetime
from pathlib import Path
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
# 添加导包路径
import sys
import os
sys.path.insert(0, os.path.join(BASE_DIR, 'apps'))
STATIC_ROOT = os.path.join(os.path.dirname(os.path.dirname(BASE_DIR)), 'front_end_pc/static')
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
# 由于没有公钥,无法验证下列签名: NO_PUBKEY 9165938D90FDDD2E
# sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 9165938D90FDDD2E
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '8l7jsblq%pndqi1tzh*lc#k6mq=w8xqriv5q2ivxqr2aqdap4c'
"""
/usr/sbin/nginx:主程序,启动文件
/etc/nginx:存放配置文件
/var/www/html:存放项目目录
/var/log/nginx:存放日志
sudo /usr/sbin/nginx 启动Nginx
sudo /usr/sbin/nginx -s stop 停止
"""
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False
ALLOWED_HOSTS = ['*','http://127.0.0.1:8002','http://127.0.0.1:8001','http://127.0.0.1:8000','http://127.0.0.1:80','http://192.168.1.101:8000','http://192.168.1.101:8001']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'users',
'verifications',
'corsheaders',
#
'areas',
'goods',
'contents',
# 注册富文本编辑器
'ckeditor', # 富文本编辑器
'ckeditor_uploader', # 富文本编辑器上传图片模块
'django_crontab', # 定时任务
'haystack',
'carts',
'orders',
'payment',
]
# 支付宝配置
ALIPAY_APPID = "2016101300672735"
ALIPAY_URL = "https://openapi.alipaydev.com/gateway.do"
ALIPAY_DEBUG = True
# 账号: [email protected]
# 密码:111111
# Haystack
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
'URL': 'http://192.168.1.101:9200/', # 此处为elasticsearch运行的服务器ip地址,端口号固定为9200
'INDEX_NAME': 'haoke', # 指定elasticsearch建立的索引库的名称
},
}
# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
# 定时任务
CRONJOBS = [
# 每5分钟执行一次生成主页静态文件
('*/1 * * * *', 'contents.crons.generate_static_index_html', '>> /home/pyvip/hualong/haoke_mall/log/crontab.log')
]
# 解决crontab中文问题
CRONTAB_COMMAND_PREFIX = 'LANG_ALL=zh_cn.UTF-8'
# 富文本编辑器ckeditor配置
CKEDITOR_CONFIGS = {
'default': {
'toolbar': 'full', # 工具条功能
'height': 300, # 编辑器高度
# 'width': 300, # 编辑器宽
},
}
CKEDITOR_UPLOAD_PATH = '' # 上传图片保存路径,使用了FastDFS,所以此处设为''
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# CORS
CORS_ORIGIN_WHITELIST = (
'http://192.168.110.215:8002',
'http://127.0.0.1:8080',
'http://127.0.0.1:8081',
'http://127.0.0.1:8000',
'http://127.0.0.1:8001',
'http://127.0.0.1:8002',
'http://127.0.0.1:80',
'http://0.0.0.0:9000',
'http://0.0.0.0:8000',
'http://0.0.0.0:8001',
'http://0.0.0.0:8002',
# 'localhost',
'http://192.168.222.1:8080',
'http://192.168.1.101:8002',
'http://192.168.1.101:8001',
'http://192.168.1.101:8000',
'http://api.meiduo.site',
)
CORS_ALLOW_CREDENTIALS = True # 允许携带cookie
# HWFZCXBBLTRBVYOG
# 以下是邮件配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
#发送邮件的邮箱
EMAIL_HOST_USER = '[email protected]'
#在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = 'DZWFXIWBGFSYSDHZ'
#收件人看到的发件人
EMAIL_FROM = '好课商城'
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
),
# 异常处理
'EXCEPTION_HANDLER': 'haoke_mall.utils.exceptions.exception_handler',
# 分页
'DEFAULT_PAGINATION_CLASS': 'haoke_mall.utils.pagination.StandardResultsSetPagination',
}
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
'JWT_RESPONSE_PAYLOAD_HANDLER': 'users.utils.jwt_response_payload_handler',
}
AUTHENTICATION_BACKENDS = [
'users.utils.UsernameMobileAuthBackend',
]
ROOT_URLCONF = 'haoke_mall.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 = 'haoke_mall.wsgi.application'
AUTH_USER_MODEL = 'users.User'
# Database
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'HOST': '127.0.0.1', # 数据库主机
'PORT': 3306, # 数据库端口
'USER': 'root', # 数据库用户名
'PASSWORD': 'qwe123', # 数据库用户密码
'NAME': 'hualong' # 数据库名字
}
}
CACHES = {
"verify_codes": { # 存储验证码
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/2",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
"session": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
"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",
}
},
"cart": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/4",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = "session"
# Password validation
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
# DRF扩展
REST_FRAMEWORK_EXTENSIONS = {
# 缓存时间
'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 * 60,
# 缓存存储
'DEFAULT_USE_CACHE': 'default',
}
# django文件存储
DEFAULT_FILE_STORAGE = 'haoke_mall.utils.fastdfs.fdfs_storage.FastDFSStorage'
# FastDFS
FDFS_URL = 'http://192.168.1.101:8888/'
FDFS_CLIENT_CONF = os.path.join(BASE_DIR, 'utils/fastdfs/client.conf')
# 生成的静态html文件保存目录
GENERATED_STATIC_HTML_FILES_DIR = os.path.join(os.path.dirname(os.path.dirname(BASE_DIR)), 'front_end_pc')
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.1/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.1/howto/static-files/
STATIC_URL = '/static/'
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(os.path.dirname(BASE_DIR), "logs/meiduo.log"), # 日志文件的位置
'maxBytes': 300 * 1024 * 1024,
'backupCount': 10,
'formatter': 'verbose'
},
},
'loggers': { # 日志器
'django': { # 定义了一个名为django的日志器
'handlers': ['console', 'file'], # 可以同时向终端与文件中输出日志
'propagate': True, # 是否继续传递日志信息
'level': 'INFO', # 日志器接收的最低日志级别
},
}
}
4.访问测试部署是否成功:
1.直接访问前端服务器的接口:127.0.0.1:8000 看看前端显示是否正常
2.访问127.0.0.1:8001 后端服务器是否正常返回数据
3.没有问题后,访问127.0.0.1:8000 进行商品的购买操作,没有问题的话
4到此项目部署成功了