luffyapi~settings
目录
如下是内容
"""
Django settings for luffyapi project.
Generated by 'django-admin startproject' using Django 2.0.7.
For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""
import os, sys
# BASE_DIR现在是小luffyapi
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 代码将BASE_DIR添加到了环境变量,pycharm开发就可以采用Sources Root小技巧
sys.path.append(BASE_DIR)
# apps文件夹要添加到环境变量中,那apps下面的模块就可以直接被注册了
APPS_DIR = os.path.join(BASE_DIR, 'apps')
sys.path.append(APPS_DIR)
# 加载自定义配置名称空间
from .const import *
# django的安全码,就是一串普通字符串,很多插件就是用它作为安全码,所有不能泄露
SECRET_KEY = 'pq#z#uzvm9$6k%go#wn4*^q9^^s&_q&gra(tsrv4whhx%-4@ab'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
# xadmin主体模块
'xadmin',
# 渲染表格模块
'crispy_forms',
# 为模型通过版本控制,可以回滚数据
'reversion',
# cors插件
'corsheaders',
'user',
'home',
'course',
'order',
]
# 自定义User表
AUTH_USER_MODEL = 'user.User'
MIDDLEWARE = [
'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插件
'corsheaders.middleware.CorsMiddleware'
]
# 允许跨域源
CORS_ORIGIN_ALLOW_ALL = True
# 允许的请求头
CORS_ALLOW_HEADERS = (
"accept",
"accept-encoding",
"authorization",
"content-type",
"dnt",
"origin",
"user-agent",
"x-csrftoken",
"x-requested-with",
# 额外允许的请求头
'token',
)
ROOT_URLCONF = 'luffyapi.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 = 'luffyapi.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'luffy',
'USER': 'luffy',
'PASSWORD': 'Luffy123?',
'HOST': 'localhost',
'PORT': 3306
}
}
import pymysql
pymysql.install_as_MySQLdb()
# Password validation
# https://docs.djangoproject.com/en/2.0/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/2.0/topics/i18n/
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/
# 后台资源配置
STATIC_URL = '/static/'
# 前台资源配置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# drf-jwt配置
import datetime
JWT_AUTH = {
# token过期时间
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
# token前缀
'JWT_AUTH_HEADER_PREFIX': 'LUFFY',
}
# drf配置
REST_FRAMEWORK = {
# 渲染
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
# jwt认证
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
],
# 权限
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
],
# 频率
'DEFAULT_THROTTLE_CLASSES': [],
# 异常
'EXCEPTION_HANDLER': 'utils.exception.exception_handler',
# 频率限制
'DEFAULT_THROTTLE_RATES': {
'sms': '1/min'
}
}
# django自带logging,但是默认只往控制台记录,所以要明文配置一下
# 真实项目上线后,日志文件打印级别不能过低,因为一次日志记录就是一次文件io操作
#diango默认的logging 是监控证项目进行记录的但是只记录在控制台 但是我的在setting里面写的是 不但要把记录在控制台,还要
#记录在这个我的文件里面 需要在setting里面配置 ,我可以手动在utils里面配置 logger 我的所有页面需要使用logger记录
#直接导入就可以了 我需要记录的比如在付款的时候 需要记录 在这个下订单的时候需要记录
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.utils.log.RequireDebugTrue',
},
},
'handlers': {
'console': {
# 实际开发建议使用WARNING
'level': 'DEBUG',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'file': {
# 实际开发建议使用WARNING、ERROR
'level': 'WARNING',
'class': 'logging.handlers.RotatingFileHandler',
# 日志位置,日志文件名,日志保存目录必须手动创建,注:这里的文件路径要注意BASE_DIR代表的是小luffyapi
'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "luffy.log"),
# 日志文件的最大值,这里我们设置300M
'maxBytes': 300 * 1024 * 1024,
# 日志文件的数量,设置最大日志数量为10
'backupCount': 10,
# 日志格式:详细格式
'formatter': 'verbose',
# 文件内容编码
'encoding': 'utf-8'
},
'file2': {
# 实际开发建议使用WARNING、ERROR
'level': 'ERROR',
'class': 'logging.handlers.RotatingFileHandler',
# 日志位置,日志文件名,日志保存目录必须手动创建,注:这里的文件路径要注意BASE_DIR代表的是小luffyapi
'filename': os.path.join(os.path.dirname(BASE_DIR), "logs", "dg.log"),
# 日志文件的最大值,这里我们设置300M
'maxBytes': 300 * 1024 * 1024,
# 日志文件的数量,设置最大日志数量为10
'backupCount': 10,
# 日志格式:详细格式
'formatter': 'verbose',
# 文件内容编码
'encoding': 'utf-8'
},
},
# 日志对象
'loggers': {
'django': {
'handlers': ['console', 'file'],
'propagate': True, # 是否让日志信息继续冒泡给其他的日志处理系统
},
}
}
# django的缓存配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/10",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 10000},
"DECODE_RESPONSES": True,
"PASSWORD": "Admin123",
}
}
}
""" 标准三流
import sys
sys.stderr.write('aaaaaaa/n')
sys.stdout.write('bbbbbbb/n')
res = sys.stdin.readline()
print(res)
"""
# 后台基URL
BASE_URL = 'http://127.0.0.1:8000'
# 前台基URL
LUFFY_URL = 'http://127.0.0.1:8080'
# 支付宝同步异步回调接口配置
# 后台异步回调接口
NOTIFY_URL = BASE_URL + "/order/success/"
# 前台同步回调接口,没有 / 结尾
RETURN_URL = LUFFY_URL + "/pay/success"
logging注意地方
5)日志logging
i)import logging 是Python解释器自带的(os、sys)
ii)django项目加载settings配置,加载了LOGGING的配置字典,加载了配置中的所有logger
logger(打印者)会有handler(输出位置),handler会有formatter(打印格式)和filter(信息过滤器)
iii)提供logging模块的getLogger('logger名')方法来获取打印者,调用日志打印功能
iv)打印级别有5种:debug、info、warning、error、critical,自己根据需求选择,你将要打印的信息定义为什么级别,你就采用什么级别进行打印
v)handler可以设置收纳的级别信息,如果file handler设置了收纳级别为WARNING,那用logger完成五种几个的各一个信息打印,只有warning及以上级别会被记录到file中
luffyapi/utils/logging.py
import logging
logger = logging.getLogger('django')
luffyapi/utils/exception.py
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.views import Response
from rest_framework import status
from utils.logging import logger
import logging
logging.getLogger('django')
def exception_handler(exc, context):
response = drf_exception_handler(exc, context)
if response is None:
# 记录服务器异常
logger.critical('%s' % exc)
response = Response({'detail': '服务器异常,请重试...'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return response
luffyapi/apps/order/views.py
from rest_framework.viewsets import GenericViewSet, ViewSet
from rest_framework.mixins import CreateModelMixin
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from utils.response import APIResponse
from . import models, serializers
# 支付接口
class PayViewSet(GenericViewSet, CreateModelMixin):
permission_classes = [IsAuthenticated]
queryset = models.Order.objects.all()
serializer_class = serializers.PaySerializer
# 重写create方法,返回pay_url,pay_url是在serializer对象中,所以要知道serializer
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
return Response(serializer.context['pay_url'])
from utils.logging import logger
# 支付回调接口
class SuccessViewSet(ViewSet):
authentication_classes = ()
permission_classes = ()
# 支付宝同步回调给前台,在同步通知给后台处理
def get(self, request, *args, **kwargs):
# return Response('后台已知晓,Over!!!')
# 不能在该接口完成订单修改操作
# 但是可以在该接口中校验订单状态(已经收到支付宝post异步通知,订单已修改),告诉前台
# print(type(request.query_params)) # django.http.request.QueryDict
# print(type(request.query_params.dict())) # dict
out_trade_no = request.query_params.get('out_trade_no')
try:
models.Order.objects.get(out_trade_no=out_trade_no, order_status=1)
return APIResponse(result=True)
except:
return APIResponse(1, 'error', result=False)
# 支付宝异步回调处理
def post(self, request, *args, **kwargs):
try:
result_data = request.data.dict()
out_trade_no = result_data.get('out_trade_no')
signature = result_data.pop('sign')
from libs import iPay
result = iPay.alipay.verify(result_data, signature)
if result and result_data["trade_status"] in ("TRADE_SUCCESS", "TRADE_FINISHED"):
# 完成订单修改:订单状态、流水号、支付时间
models.Order.objects.filter(out_trade_no=out_trade_no).update(order_status=1)
# 完成日志记录
logger.warning('%s订单支付成功' % out_trade_no)
return Response('success')
else:
logger.error('%s订单支付失败' % out_trade_no)
except:
pass
return Response('failed')