增加area tdevice表

This commit is contained in:
caoqianming 2022-05-09 14:45:12 +08:00
parent 821d6cf2db
commit 0ab3ae31af
24 changed files with 520 additions and 27 deletions

0
apps/am/__init__.py Executable file
View File

3
apps/am/admin.py Executable file
View File

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

6
apps/am/apps.py Executable file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class AemConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.am'

View File

@ -0,0 +1,64 @@
# Generated by Django 3.2.12 on 2022-05-09 01:05
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('system', '0004_auto_20220421_1511'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Access',
fields=[
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('type', models.PositiveSmallIntegerField(choices=[(10, '准入'), (20, '禁入')], verbose_name='准入类型')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='Area',
fields=[
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('name', models.CharField(max_length=20, verbose_name='名称')),
('level', models.PositiveSmallIntegerField(verbose_name='区域等级')),
('sort_str', models.CharField(default='1', max_length=12, verbose_name='排序字符')),
('visitor_no', models.BooleanField(default=True, verbose_name='不准许访客')),
('rparty_no', models.BooleanField(default=True, verbose_name='不准许相关方')),
('third_info', models.JSONField(blank=True, default=dict, verbose_name='三方信息')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='area_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('manager', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='区域负责人')),
('posts_access', models.ManyToManyField(through='am.Access', to='system.Post')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='area_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='access',
name='area',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='am.area', verbose_name='关联区域'),
),
migrations.AddField(
model_name='access',
name='post',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='system.post', verbose_name='关联岗位'),
),
]

0
apps/am/migrations/__init__.py Executable file
View File

37
apps/am/models.py Executable file
View File

@ -0,0 +1,37 @@
from django.db import models
from apps.system.models import Post, User
from apps.utils.models import BaseModel, CommonAModel
# Create your models here.
class Area(CommonAModel):
"""
地图区域
"""
name = models.CharField('名称', max_length=20)
level = models.PositiveSmallIntegerField('区域等级')
sort_str = models.CharField('排序字符', max_length=12, default='1')
manager = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name='区域负责人')
visitor_no = models.BooleanField('不准许访客', default=True)
rparty_no = models.BooleanField('不准许相关方', default=True)
posts_access = models.ManyToManyField(Post, through='am.access')
third_info = models.JSONField('三方信息', default=dict,
null=False, blank=True)
class Access(BaseModel):
"""
准入权限
"""
ACCESS_IN_YES = 10
ACCESS_IN_NO = 20
ACCESS_CHOICE = (
(ACCESS_IN_YES, '准入'),
(ACCESS_IN_NO, '禁入')
)
type = models.PositiveSmallIntegerField('准入类型', choices=ACCESS_CHOICE)
area = models.ForeignKey(Area, verbose_name='关联区域',
on_delete=models.CASCADE)
post = models.ForeignKey(Post, verbose_name='关联岗位',
on_delete=models.CASCADE)

8
apps/am/serializers.py Normal file
View File

@ -0,0 +1,8 @@
from apps.am.models import Area
from apps.utils.serializers import CustomModelSerializer
class AreaSimpleSerializer(CustomModelSerializer):
class Meta:
model = Area
fields = ['id', 'name', 'level']

3
apps/am/tests.py Executable file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

3
apps/am/views.py Executable file
View File

@ -0,0 +1,3 @@
from django.shortcuts import render
# Create your views here.

View File

@ -97,7 +97,7 @@ class PTaskViewSet(CustomModelViewSet):
interval, _ = IntervalSchedule.objects.get_or_create(
**interval_, defaults=interval_)
data['interval'] = interval.id
except:
except Exception:
raise ParseError(**SCHEDULE_WRONG)
if timetype == 'crontab' and crontab_:
data['interval'] = None
@ -106,7 +106,7 @@ class PTaskViewSet(CustomModelViewSet):
crontab, _ = CrontabSchedule.objects.get_or_create(
**crontab_, defaults=crontab_)
data['crontab'] = crontab.id
except:
except Exception:
raise ParseError(**SCHEDULE_WRONG)
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
@ -131,7 +131,7 @@ class PTaskViewSet(CustomModelViewSet):
interval, _ = IntervalSchedule.objects.get_or_create(
**interval_, defaults=interval_)
data['interval'] = interval.id
except:
except Exception:
raise ParseError(**SCHEDULE_WRONG)
if timetype == 'crontab' and crontab_:
data['interval'] = None
@ -142,7 +142,7 @@ class PTaskViewSet(CustomModelViewSet):
crontab, _ = CrontabSchedule.objects.get_or_create(
**crontab_, defaults=crontab_)
data['crontab'] = crontab.id
except:
except Exception:
raise ParseError(**SCHEDULE_WRONG)
instance = self.get_object()
serializer = self.get_serializer(instance, data=data)
@ -166,6 +166,7 @@ class PTaskResultViewSet(ListModelMixin, RetrieveModelMixin, CustomGenericViewSe
queryset = TaskResult.objects.all()
serializer_class = PTaskResultSerializer
ordering = ['-date_created']
lookup_field = 'task_id'
class DictTypeViewSet(CustomModelViewSet):

View File

@ -1,5 +1,6 @@
from apps.utils.xunxi import XxClient
from apps.utils.dahua import DhClient
from apps.utils.speaker import SpClient
dhClient = DhClient()
xxClient = XxClient()
spClient = SpClient()

View File

@ -0,0 +1,35 @@
# Generated by Django 3.2.12 on 2022-05-09 01:05
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('am', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='TDevice',
fields=[
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('type', models.PositiveSmallIntegerField(choices=[(10, '定位基站'), (20, '定位信标'), (30, '定位标签'), (40, 'aoa引擎'), (50, '音响'), (60, '视频通道'), (70, '闸机通道'), (80, '面板机')], verbose_name='设备类型')),
('code', models.CharField(max_length=20, verbose_name='设备唯一标识')),
('location', models.JSONField(blank=True, default=dict, verbose_name='位置信息')),
('third_info', models.JSONField(blank=True, default=dict, verbose_name='三方信息')),
('area', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='am.area', verbose_name='所在区')),
('areas', models.ManyToManyField(related_name='tareas', to='am.Area', verbose_name='覆盖区')),
],
options={
'abstract': False,
},
),
]

View File

@ -1,3 +1,41 @@
from django.db import models
from apps.am.models import Area
from apps.utils.models import BaseModel
# Create your models here.
class TDevice(BaseModel):
"""
三方设备补充信息
"""
DEVICE_BLG = 10
DEVICE_IBEACON = 20
DEVICE_BLT = 30
DEVICE_AOA = 40
DEVICE_SPEAKER = 50
DEVICE_VCHANNEL = 60
DEVICE_DCHANNEL = 70
DEVICE_PANEL = 80
DEVICE_CHOICE = (
(DEVICE_BLG, '定位基站'),
(DEVICE_IBEACON, '定位信标'),
(DEVICE_BLT, '定位标签'),
(DEVICE_AOA, 'aoa引擎'),
(DEVICE_SPEAKER, '音响'),
(DEVICE_VCHANNEL, '视频通道'),
(DEVICE_DCHANNEL, '闸机通道'),
(DEVICE_PANEL, '面板机')
)
type = models.PositiveSmallIntegerField('设备类型', choices=DEVICE_CHOICE)
code = models.CharField('设备唯一标识', max_length=20)
location = models.JSONField('位置信息', default=dict,
null=False, blank=True)
area = models.ForeignKey(Area, on_delete=models.CASCADE,
verbose_name='所在区', null=True, blank=True)
areas = models.ManyToManyField(Area, verbose_name='覆盖区',
related_name='tareas')
third_info = models.JSONField('三方信息', default=dict,
null=False, blank=True)

View File

@ -1,5 +1,7 @@
from rest_framework import serializers
from apps.am.models import Area
class RequestCommonSerializer(serializers.Serializer):
method_choice = (
@ -13,3 +15,21 @@ class RequestCommonSerializer(serializers.Serializer):
params = serializers.JSONField(label='请求参数', required=False, allow_null=True)
json = serializers.JSONField(label='请求body(json格式)', required=False, allow_null=True)
code = serializers.CharField(label='请求短标识', required=False, allow_null=True)
class BindAreaSerializer(serializers.Serializer):
codes = serializers.ListField(child=serializers.CharField(), label='标识列表')
area = serializers.PrimaryKeyRelatedField(queryset=Area.objects.all(),
label="区域ID")
class LabelLocationSerializer(serializers.Serializer):
code = serializers.CharField(label='设备唯一标识')
location = serializers.JSONField(label='坐标信息')
class BindAreasSerializer(serializers.Serializer):
codes = serializers.ListField(child=serializers.CharField(), label='标识列表')
areas = serializers.PrimaryKeyRelatedField(queryset=Area.objects.all(),
label="区域ID列表",
required=False, many=True)

View File

@ -88,5 +88,25 @@ dhapis = {
# 寻息API接口
xxapis = {
"blg_list": {
"url": "/api/devicesV3/blgs",
"method": "post"
},
"ibeacon_list": {
"url": "/api/devicesV3/ibeacons",
"method": "post"
}
}
# 音响API接口
spapis = {
"user_login": {
"url": "/api/users/login",
"method": "post"
},
"device_list": {
"url": "/api/devices",
"method": "get"
}
}

View File

@ -1,6 +1,7 @@
from django.urls import path, include
from rest_framework import routers
from apps.third.views import DahuaTestView, DhCommonViewSet, XxCommonViewSet, XxTestView
from apps.third.views import DahuaTestView, DhCommonViewSet, SpTestView, XxCommonViewSet, XxTestView
from apps.third.views_d import VChannelViewSet
API_BASE_URL = 'api/third/'
HTML_BASE_URL = 'third/'
@ -8,9 +9,10 @@ HTML_BASE_URL = 'third/'
router = routers.DefaultRouter()
router.register('xunxi', XxCommonViewSet, basename='api_xunxi')
router.register('dahua', DhCommonViewSet, basename='api_dahua')
router.register('vchannel', VChannelViewSet, basename='vchannel')
urlpatterns = [
path(API_BASE_URL, include(router.urls)),
path(API_BASE_URL + 'dahua/test/', DahuaTestView.as_view()),
path(API_BASE_URL + 'xunxi/test/', XxTestView.as_view()),
path(API_BASE_URL + 'speaker/test/', SpTestView.as_view()),
]

View File

@ -1,9 +1,8 @@
from rest_framework.exceptions import ParseError, APIException
from apps.third.tapis import dhapis, xxapis
from apps.third.tapis import dhapis, xxapis, spapis
from apps.third.erros import TAPI_CODE_WRONG
from apps.third.clients import dhClient
from apps.third.clients import dhClient, spClient, xxClient
from apps.utils.mixins import MyLoggingMixin
from apps.third.clients import xxClient
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated, IsAdminUser
@ -31,6 +30,22 @@ class DahuaTestView(MyLoggingMixin, APIView):
return Response(res)
class SpTestView(APIView):
"""
音响测试接口
"""
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
"""
音响测试接口
音响测试接口
"""
_, res = spClient.request(**spapis['device_list'])
return Response(res)
class XxTestView(APIView):
"""
寻息测试接口
@ -58,11 +73,11 @@ class XxListener(stomp.ConnectionListener):
print('received a message "%s"' % frame.body)
if settings.XX_ENABLED:
c = stomp.Connection([(settings.XX_MQ_HOST, settings.XX_MQ_PORT)])
c.set_listener('', XxListener())
c.connect(settings.XX_USERNAME, settings.XX_LICENCE)
c.subscribe(settings.XX_QUEUE, id='')
# if settings.XX_ENABLED:
# c = stomp.Connection([(settings.XX_MQ_HOST, settings.XX_MQ_PORT)])
# c.set_listener('', XxListener())
# c.connect(settings.XX_USERNAME, settings.XX_LICENCE)
# c.subscribe(settings.XX_QUEUE, id='')
class XxCommonViewSet(CreateModelMixin, CustomGenericViewSet):
@ -77,11 +92,11 @@ class XxCommonViewSet(CreateModelMixin, CustomGenericViewSet):
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
if vdata.get('code', ''):
dhapi = dhapis.get(vdata['code'], None)
if dhapi is None:
xxapi = xxapis.get(vdata['code'], None)
if xxapi is None:
raise ParseError(**TAPI_CODE_WRONG)
vdata['url'] = dhapi['url']
vdata['method'] = dhapi['method']
vdata['url'] = xxapi['url']
vdata['method'] = xxapi['method']
_, res = xxClient.request(
url=vdata['url'],
method=vdata.get('method', 'post'),

116
apps/third/views_d.py Normal file
View File

@ -0,0 +1,116 @@
from apps.third.models import TDevice
from apps.third.serializers import BindAreaSerializer, LabelLocationSerializer
from apps.utils.viewsets import CustomGenericViewSet
from rest_framework.mixins import ListModelMixin
from apps.third.clients import xxClient, dhClient
from apps.third.tapis import xxapis, dhapis
from rest_framework.response import Response
from rest_framework.serializers import Serializer
from rest_framework.decorators import action
from apps.am.models import Area
# class BlgViewSet(ListModelMixin, CustomGenericViewSet):
# """
# 定位基站接口
# """
# perms_map = {'get': '*'} # 权限标识
# serializer_class = Serializer
# def list(self, request, *args, **kwargs):
# """
# 定位基站列表
# 定位基站列表
# """
# data = request.data
# _, res = xxClient.request(**xxapis['blg_list'], json=data)
# return Response(res)
# class IbeaconViewSet(CustomGenericViewSet):
# """
# 信标接口
# """
# perms_map = {'get': '*'} # 权限标识
# serializer_class = Serializer
# def list(self, request, *args, **kwargs):
# """
# 信标列表
# 定位基站列表
# """
# data = request.data
# _, res = xxClient.request(**xxapis['blg_list'], json=data)
# return Response(res)
class DChannelViewSet(CustomGenericViewSet):
"""
闸机接口
"""
pass
class VChannelViewSet(CustomGenericViewSet):
"""
视频接口
"""
@action(methods=['post'], detail=False, perms_map={'post': '*'},
serializer_class=Serializer)
def page(self, request):
request.data.update({'channelTypeList': ["1"]})
_, res = dhClient.request(**dhapis['channel_list'], json=request.data)
return Response(res)
@action(methods=['post'], detail=False, perms_map={'post': 'dchannel:label_location'},
serializer_class=LabelLocationSerializer)
def label_location(self, request):
"""
标注坐标位置
标注坐标位置
"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.vdata
td = TDevice.objects.filter(code=vdata['code']).first()
if td:
td.location = vdata['location']
td.update_by = request.user
td.save()
else:
td = TDevice()
td.type = TDevice.DEVICE_VCHANNEL
td.code = vdata['code']
td.location = vdata['location']
td.create_by = request.user
td.save()
return Response()
@action(methods=['post'], detail=False, perms_map={'post': 'dchannel:bind_area'},
serializer_class=BindAreaSerializer)
def bind_area(self, request):
"""
绑定所在区域
绑定所在区域
"""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.vdata
area = Area.objects.get(id=vdata['area'])
for i in vdata['codes']:
td = TDevice.objects.filter(code=i['code']).first()
if td:
td.area = area
td.update_by = request.user
td.save()
else:
td = TDevice()
td.type = TDevice.DEVICE_VCHANNEL
td.code = i['code']
td.area = area
td.create_by = request.user
td.save()
return Response()

View File

@ -88,7 +88,7 @@ class DhClient:
r = getattr(requests, method)('{}{}'.format(settings.DAHUA_BASE_URL, url),
headers=self.headers, params=params, json=json,
timeout=timeout, files=files, verify=False)
except:
except Exception:
if raise_exception:
raise APIException(**DH_REQUEST_ERROR)
return 'error', DH_REQUEST_ERROR
@ -112,6 +112,3 @@ class DhClient:
if raise_exception:
raise APIException(**DH_REQUEST_ERROR)
return 'error', DH_REQUEST_ERROR
dhClient = DhClient()

View File

@ -1,4 +1,5 @@
XX_REQUEST_ERROR = {"code": "xx_request_error", "detail": "寻息接口访问异常"}
DH_REQUEST_ERROR = {"code": "dh_request_error", "detail": "大华接口访问异常"}
SP_REQUEST_ERROR = {"code": "sp_request_error", "detail": "音响接口访问异常"}
SIGN_MAKE_FAIL = {"code": "sign_make_fail", "detail": "签名照生成失败,请重新上传"}
PKS_ERROR = {"code": "pks_error", "detail": "未获取到主键列表"}

109
apps/utils/speaker.py Normal file
View File

@ -0,0 +1,109 @@
import time
from threading import Thread
import requests
# from django.conf import settings
from server import settings
from rest_framework.exceptions import APIException, ParseError
from apps.utils.errors import SP_REQUEST_ERROR
from apps.utils.tools import print_roundtrip
requests.packages.urllib3.disable_warnings()
class SpClient:
"""
音响接口
"""
def __init__(self, username=settings.SP_USERNAME,
password=settings.SP_PASSWORD) -> None:
if not settings.SP_ENABLED:
return None
self.username = username
self.password = password
self.headers = {}
self.isGetingToken = False
self.isRuning = True
self.t = None # 线程
self.setup()
def _get_token_loop(self):
while self.isRuning:
params = {
"user": {
"email": self.username,
"password": self.password
}
}
r = requests.post(params=params,
url=settings.SP_BASE_URL + '/api/users/login', verify=False)
if r.status_code == 200:
ret = r.json()
self.headers['Authorization'] = 'bearer ' + ret['user']['token']
time.sleep(3600)
def get_token(self):
self.isGetingToken = True
params = {
'grant_type': 'client_credentials',
'client_id': self.client_id,
'client_secret': self.client_secret
}
r = requests.post(params=params, url=settings.SP_BASE_URL + '/evo-apigw/evo-oauth/oauth/token', verify=False)
if r.status_code == 200:
ret = r.json()
print(ret)
self.headers['Authorization'] = 'bearer ' + ret['user']['token']
self.isGetingToken = False
def setup(self):
t = Thread(target=self._get_token_loop, args=(), daemon=True)
t.start()
def __del__(self):
"""
自定义销毁
"""
self.isRuning = False
# self.t.join()
def request(self, url: str, method: str, params=dict(), json=dict(), timeout=10,
file_path_rela=None, raise_exception=True):
if self.isGetingToken:
req_num = 0
while True:
time.sleep(0.5)
if not self.isGetingToken:
self.request(url, method, params, json, timeout, file_path_rela, raise_exception)
req_num = req_num + 1
if req_num > 4:
break
else:
files = None
if file_path_rela: # 相对路径
files = {'file': open(settings.BASE_DIR + file_path_rela, 'rb')}
try:
if params:
url = url.format(**params)
r = getattr(requests, method)('{}{}'.format(settings.SP_BASE_URL, url),
headers=self.headers, params=params, json=json,
timeout=timeout, files=files, verify=False)
except Exception:
if raise_exception:
raise APIException(**SP_REQUEST_ERROR)
return 'error', SP_REQUEST_ERROR
# if settings.DEBUG:
# print_roundtrip(r)
if r.status_code == 200:
ret = r.json()
if 'code' in ret and ret['code'] not in ['0', '100', '00000', '1000', 0, 100, 1000]:
detail = '音响错误:{}'.format(str(ret['msg']))
err_detail = dict(detail=detail, code='sp_'+str(ret['code']))
if raise_exception:
raise ParseError(**err_detail)
return 'fail', dict(detail=detail, code='sp_'+str(ret['code']))
return 'success', ret
if raise_exception:
raise APIException(**SP_REQUEST_ERROR)
return 'error', SP_REQUEST_ERROR

View File

@ -14,6 +14,7 @@ from apps.utils.mixins import CustomDestoryModelMixin, MyLoggingMixin
from apps.utils.permission import ALL_PERMS, RbacPermission, get_user_perms_map
from apps.utils.queryset import get_child_queryset2
from apps.utils.serializers import PkSerializer
from rest_framework.throttling import UserRateThrottle
class CustomGenericViewSet(MyLoggingMixin, GenericViewSet):
@ -21,6 +22,7 @@ class CustomGenericViewSet(MyLoggingMixin, GenericViewSet):
增强的GenericViewSet
"""
perms_map = {} # 权限标识
throttle_classes = [UserRateThrottle]
logging_methods = ['POST', 'PUT', 'PATCH', 'DELETE']
ordering_fields = '__all__'
filter_fields = '__all__'

View File

@ -73,8 +73,8 @@ class XxClient:
else:
r = getattr(requests, method)('{}{}'.format(settings.XX_BASE_URL, url),
params=params, json=json, timeout=timeout, verify=False)
# if settings.DEBUG:
# print_roundtrip(r)
if settings.DEBUG:
print_roundtrip(r)
ret = r.json()
if ret.get('errorCode') == '1060000':
self.get_token() # 重新获取token

View File

@ -53,7 +53,8 @@ INSTALLED_APPS = [
'apps.auth1',
'apps.monitor',
'apps.wf',
'apps.hrm'
'apps.hrm',
'apps.am'
]
MIDDLEWARE = [
@ -180,6 +181,10 @@ REST_FRAMEWORK = {
# 'UNAUTHENTICATED_USER': None,
# 'UNAUTHENTICATED_TOKEN': None,
'EXCEPTION_HANDLER': 'apps.utils.exceptions.custom_exception_hander',
'DEFAULT_THROTTLE_RATES': {
'anon': '1/second',
'user': '1/second'
}
}
# simplejwt配置
SIMPLE_JWT = {
@ -327,6 +332,13 @@ XX_USERNAME = conf.XX_USERNAME
XX_BUILDID = conf.XX_BUILDID
XX_QUEUE = conf.XX_QUEUE
# 喇叭配置
SP_ENABLED = conf.SP_ENABLED
SP_BASE_URL = conf.SP_BASE_URL
SP_USERNAME = conf.SP_USERNAME
SP_PASSWORD = conf.SP_PASSWORD
# 运维相关
SD_PWD = conf.SD_PWD
BACKUP_PATH = conf.BACKUP_PATH