Procházet zdrojové kódy

优化项目结构,使用三级视图方法和model序列化器,实现物联网卡数据展示接口和数据插入接口

yf_fyh před 3 roky
rodič
revize
b5922a3edf

+ 3 - 2
apps/IOTCard/models.py

@@ -1,11 +1,12 @@
 from django.db import models
 import django.utils.timezone as timezone
 
+
 # Create your models here.
 class PlatSimInfo(models.Model):
     OPERATORS_CHOICE = [
         (1, "合宙"),
-        (2, "企朋"), # 企朋和SIMBOSS是同一单位
+        (2, "企朋"),  # 企朋和SIMBOSS是同一单位
         (3, "未知")
     ]
     TYPE_CHOICE = [
@@ -31,4 +32,4 @@ class PlatSimInfo(models.Model):
     upl_time = models.DateTimeField(u'更新时间', default=timezone.now)
 
     class Meta:
-        db_table = "plat_sim_info"
+        db_table = "plat_sim_info"

+ 20 - 27
apps/IOTCard/serializers.py

@@ -1,31 +1,24 @@
 from rest_framework import serializers
 
+from .models import PlatSimInfo
 
-class PlatSimInfoSerializer(serializers.Serializer):
-    id = serializers.IntegerField(help_text="记录ID", read_only=True)
-    simId = serializers.CharField(help_text="sim卡号", required=False)
-    sim_operators = serializers.IntegerField(help_text="物联网卡商", read_only=True)
-    input_type = serializers.IntegerField(help_text="输入类型", read_only=True)
-    deviceId = serializers.CharField(help_text="设备号", required=False)
-    device_type = serializers.CharField(help_text="设备类型", required=False)
-    platform = serializers.IntegerField(help_text="所属平台", required=False)
-    account_status = serializers.CharField(help_text="卡状态", read_only=True)
-    active_date = serializers.CharField(help_text="激活日期", read_only=True)
-    data_plan = serializers.CharField(help_text="套餐类型", read_only=True)
-    data_usage = serializers.CharField(help_text="当月用量", read_only=True)
-    data_balance = serializers.CharField(help_text="剩余流量", read_only=True)
-    expiry_date = serializers.CharField(help_text="到期时间", read_only=True)
-    upl_time = serializers.DateTimeField(help_text='更新时间', read_only=True)
 
-    def validate_simId(self, value):
-        vlaue = vlaue.strip()
-        if len(value) < 4:
-            raise serializers.ValidationError("搜索卡号长度不能小于4位")
-        else:
-            return value
-    def validate_deviceId(self, value):
-        vlaue = vlaue.strip()
-        if len(value) < 4:
-            raise serializers.ValidationError("搜索设备号长度不能小于4位")
-        else:
-            return value
+class PlatSimInfoSerializer(serializers.ModelSerializer):
+
+    def to_representation(self, instance):
+        """to_representation自定义序列化数据的返回,针对choice字段"""
+        data = super().to_representation(instance)
+        data.update(sim_operators=instance.get_sim_operators_display())
+        data.update(input_type=instance.get_input_type_display())
+        data.update(platform=instance.get_platform_display())
+        return data
+
+    class Meta:
+        model = PlatSimInfo
+        fields = '__all__'
+        read_only = ["id", "upl_time"]
+        extra_kwargs = {
+            "upl_time": {
+                "format": "%Y-%m-%d %H:%M:%S"
+            }
+        }

+ 8 - 3
apps/IOTCard/urls.py

@@ -1,9 +1,14 @@
-from django.conf.urls import url
+from rest_framework import routers
 
 from . import views
 
 app_name = 'apps.IOTCard'
 
+router = routers.SimpleRouter()
+router.register('platformsimview', views.PlatformIOTCardViewSet)
+rest_urlpatterns = router.urls
+
 urlpatterns = [
-    url(r'^base_type$', views.GetBaseType.as_view(), name='物联网卡记录'),
-]
+
+]
+urlpatterns += rest_urlpatterns

+ 101 - 7
apps/IOTCard/views.py

@@ -1,21 +1,115 @@
-from rest_framework.views import APIView
-from rest_framework.viewsets import GenericViewSet
+from rest_framework import status
+from rest_framework.viewsets import ModelViewSet
 from rest_framework.response import Response
+from rest_framework.decorators import action
+from rest_framework.serializers import ValidationError
+
+import requests
+import json
 
 from .serializers import PlatSimInfoSerializer
 from .models import PlatSimInfo
+from utils.paginations import CustomPagination
+from utils.utils import get_equip_list, Get_SIM_info
+
 
 # Create your views here.
 
-class GetBaseType(APIView):
-    def get(self, request):
+
+class PlatformIOTCardViewSet(ModelViewSet):
+    serializer_class = PlatSimInfoSerializer
+    pagination_class = CustomPagination
+    queryset = PlatSimInfo.objects.all().order_by("expiry_date")
+
+    @action(methods=['get'], detail=False, url_path='get_device_type', url_name='get_device_type')
+    def get_device_type(self, request, *args, **kwargs):
         queryset = PlatSimInfo.objects.raw("SELECT id,device_type FROM plat_sim_info GROUP BY device_type;")
         data = []
         for i in queryset:
             data.append(i.device_type)
         return Response(data)
 
+    def list(self, request, *args, **kwargs):
+        device_type = request.query_params.get("device_type")
+        deviceId = request.query_params.get("deviceId")
+        simId = request.query_params.get("simId")
+        expire_start_time = request.query_params.get("expire_start_time")
+        expire_end_time = request.query_params.get("expire_end_time")
+        queryset = self.get_queryset()
+        if device_type:
+            queryset = queryset.filter(device_type=device_type)
+        if deviceId:
+            if len(deviceId.strip()) < 4:
+                raise ValidationError("设备号长度不能小于4位")
+            queryset = queryset.filter(deviceId__icontains=deviceId.strip())
+        if simId:
+            if len(simId.strip()) < 4:
+                raise ValidationError("物联网卡号长度不能小于4位")
+            queryset = queryset.filter(simId__icontains=simId.strip())
+        if expire_start_time:
+            queryset = queryset.filter(expiry_date__range=(expire_start_time, expire_end_time))
+        page = self.paginate_queryset(queryset)
+        serializer = self.get_serializer(page, many=True)
+        return self.get_paginated_response(serializer.data)
+
+    def create(self, request, *args, **kwargs):
+        device_id = request.data.get("device_id").strip()
+        simId = request.data.get("simId").strip()
+        if len(simId) > 20 or len(simId) < 19:
+            raise ValidationError("物联网卡长度介于19-20位")
+
+        if self.get_queryset().filter(simId=simId).exists():
+            raise ValidationError("该物联网卡号已存在,请核查!")
+
+        if self.get_queryset().filter(deviceId=device_id, input_type=2).exists():
+            raise ValidationError("该设备已存在手动录入物联网卡,请核查!")
+
+        device_info_list = get_equip_list(
+            d_id=device_id,
+            isfullId=1
+        )
+        if device_info_list:
+            device_info = device_info_list[0]
+            device_type = device_info["device_type"]
+            platform = device_info["plat"]
+        else:
+            device_type = ""
+            platform = ""
+        if device_type not in ["测报灯", "孢子仪"]:
+            raise ValidationError("不支持该类型设备手动录入物联网卡!")
+        if platform == "四情平台":
+            platformid = 1
+            res = requests.post(url="http://www.yfzhwlw.com/equip_simiccid", data={"e_id": device_id, "iccid": simId})
+            if res.text != "0":
+                raise ValidationError("对应平台添加异常!")
+        elif platform == "大数据平台":
+            platformid = 2
+            res = requests.post(url="http://8.136.98.49:8002/api/api_gateway?method=forecast.send_control.device_sim",
+                                data={"device_id": device_id, "iccid": simId, "type": "change"})
+            res_json = json.loads(res.text)
+            if res_json["message"] != "":
+                raise ValidationError("对应平台添加异常!")
+        else:
+            raise ValidationError("平台不存在该设备ID,请核查!")
 
-class PlatformIOTCardViewSet(GenericViewSet):
-    queryset = PlatSimInfo.objects.all()
-    serializer_class = PlatSimInfoSerializer
+        sim_operators, account_status, active_date, data_plan, data_usage, data_balance, expiry_date = Get_SIM_info(
+            simId).get_sim_info()
+        request_data = {
+            "simId": simId,
+            "sim_operators": sim_operators,
+            "input_type": 2,
+            "deviceId": device_id,
+            "device_type": device_type,
+            "platform": platformid,
+            "account_status": account_status,
+            "active_date": active_date,
+            "data_plan": data_plan,
+            "data_usage": data_usage,
+            "data_balance": data_balance,
+            "expiry_date": expiry_date
+        }
+        serializer = self.get_serializer(data=request_data)
+        serializer.is_valid(raise_exception=True)
+        self.perform_create(serializer)
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

+ 2 - 2
apps/SearchEquip/serializers.py

@@ -1,4 +1,3 @@
-
 # coding:utf-8
 import datetime
 
@@ -10,7 +9,8 @@ class SearchEquipSerializer(serializers.Serializer):
     isfullId = serializers.IntegerField(help_text="是否完整搜索固定值1", required=False)
 
     def validate_device_id(self, value):
+        value = value.strip()
         if len(value) < 4:
             raise serializers.ValidationError("设备号长度不能小于4位")
         else:
-            return value
+            return value

+ 2 - 2
apps/SearchEquip/urls.py

@@ -5,5 +5,5 @@ from . import views
 app_name = 'apps.SearchEquip'
 
 urlpatterns = [
-    url(r'^search$', views.SearchEquip.as_view(), name='equip_search'),
-]
+    url(r'^search', views.SearchEquip.as_view(), name='equip_search'),
+]

+ 7 - 20
apps/SearchEquip/views.py

@@ -1,10 +1,9 @@
 from rest_framework.views import APIView
 from rest_framework.response import Response
 
-import json
-import requests
-
 from .serializers import SearchEquipSerializer
+from utils.utils import get_equip_list
+
 
 # Create your views here.
 
@@ -13,20 +12,8 @@ class SearchEquip(APIView):
         serializer = SearchEquipSerializer(data=request.data)
         serializer.is_valid(raise_exception=True)
         request_data = serializer.validated_data
-        d_id = request_data.get("device_id")
-        if request_data.get("isfullId"):
-            bigdata_res = requests.post("http://8.136.98.49:8002/search/equip",data={"device_id":d_id,"isfullId":"1"})
-            siqing_res = requests.post("http://www.yfzhwlw.com/search/equip",data={"device_id":d_id,"isfullId":"1"})
-        else:
-            bigdata_res = requests.post("http://8.136.98.49:8002/search/equip",data={"device_id":d_id})
-            siqing_res = requests.post("http://www.yfzhwlw.com/search/equip",data={"device_id":d_id})
-        
-        django_data = json.loads(bigdata_res.content.decode()).get("data",[])
-        siqing_data = json.loads(siqing_res.content.decode()).get("data",[])
-        data = []
-        data.extend(django_data)
-        data.extend(siqing_data)
-
-        data = sorted(data, key=lambda e: e.__getitem__('uptime'), reverse=True)
-        data = sorted(data, key=lambda e: e.__getitem__('device_id'), reverse=True)
-        return Response(data)
+        data = get_equip_list(
+            d_id=request_data.get("device_id"),
+            isfullId=request_data.get("isfullId")
+        )
+        return Response(data)

+ 2 - 2
bigdataAPI/__init__.py

@@ -1,3 +1,3 @@
 import pymysql
- 
-pymysql.install_as_MySQLdb()
+
+pymysql.install_as_MySQLdb()

+ 2 - 2
bigdataAPI/settings.py

@@ -82,7 +82,7 @@ DATABASES = {
         'NAME': 'bigdata_api',
         'USER': 'api',
         'PASSWORD': 'yfkj@6020',
-        'HOST': '127.0.0.1',
+        'HOST': '114.115.147.140',
         'PORT': 3306,
         'OPTIONS': {'charset': 'utf8mb4'}
     }
@@ -135,6 +135,6 @@ REST_FRAMEWORK = {
     'EXCEPTION_HANDLER': 'utils.exception.custom_exception_handler',
     # 修改默认返回JSON的renderer的类
     'DEFAULT_RENDERER_CLASSES': (
-        'utils.rendererresponse.customrenderer',
+        'utils.rendererresponse.CustomRender',
     ),
 }

+ 3 - 3
bigdataAPI/urls.py

@@ -14,10 +14,10 @@ Including another URLconf
     2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
 """
 # from django.contrib import admin
-from django.urls import path,include
+from django.urls import path, include
 
 urlpatterns = [
     # path('admin/', admin.site.urls),
-    path('equipmanager/',include('apps.SearchEquip.urls')),
-    path('iotcard/',include('apps.IOTCard.urls')),
+    path('equipmanager/', include('apps.SearchEquip.urls')),
+    path('iotcard/', include('apps.IOTCard.urls')),
 ]

+ 53 - 0
utils/paginations.py

@@ -0,0 +1,53 @@
+# coding:utf-8
+
+from django.core.paginator import InvalidPage
+from rest_framework.response import Response
+from rest_framework.pagination import PageNumberPagination
+from rest_framework.exceptions import NotFound
+
+
+class CustomPagination(PageNumberPagination):
+    page_size = 10
+    page_query_param = "page"
+    page_size_query_param = "page_size"
+
+    def paginate_queryset(self, queryset, request, view=None):
+        """
+        Paginate a queryset if required, either returning a
+        page object, or `None` if pagination is not configured for this view.
+        """
+        page_size = self.get_page_size(request)
+        if not page_size:
+            return None
+
+        paginator = self.django_paginator_class(queryset, page_size)
+        page_number = int(request.query_params.get(self.page_query_param, 1))
+        if page_number in self.last_page_strings:
+            page_number = int(paginator.num_pages)
+
+        page_number = min(page_number, paginator.num_pages)
+
+        try:
+            self.page = paginator.page(page_number)
+        except InvalidPage as exc:
+            msg = self.invalid_page_message.format(
+                page_number=page_number, message=str(exc)
+            )
+            raise NotFound(msg)
+
+        if paginator.num_pages > 1 and self.template is not None:
+            # The browsable API should display pagination controls.
+            self.display_page_controls = True
+
+        self.request = request
+        return list(self.page)
+
+    def get_paginated_response(self, data):
+        return Response({
+            'total_page': self.page.paginator.num_pages,
+            'total_counts': self.page.paginator.count,
+            'page_size': self.page.paginator.per_page,
+            'current_page': self.page.number,
+            'current_counts': len(data),
+            'items': data
+        })

+ 3 - 2
utils/rendererresponse.py

@@ -6,7 +6,7 @@
 from rest_framework.renderers import JSONRenderer
 
 
-class customrenderer(JSONRenderer):
+class CustomRender(JSONRenderer):
     # 重构render方法
     def render(self, data, accepted_media_type=None, renderer_context=None):
         # print(data)
@@ -22,6 +22,7 @@ class customrenderer(JSONRenderer):
                 msg = "success"
                 code = renderer_context["response"].status_code
                 payload = data
+            renderer_context["response"].status_code = 200
             ret = {
                 'code': code,
                 'msg': msg,
@@ -30,4 +31,4 @@ class customrenderer(JSONRenderer):
             # 返回JSON数据
             return super().render(ret, accepted_media_type, renderer_context)
         else:
-            return super().render(data, accepted_media_type, renderer_context)
+            return super().render(data, accepted_media_type, renderer_context)

+ 138 - 0
utils/utils.py

@@ -0,0 +1,138 @@
+import json
+import hashlib
+import time
+import requests
+from requests.auth import HTTPBasicAuth
+
+
+def get_equip_list(d_id, isfullId=0):
+    """
+    跨平台获取设备信息
+    :param d_id: 设备号
+    :param isfullId:0模糊匹配,1表示完整设备号匹配
+    :return:列表数据,相同设备号放一起,并且最近更新数据靠前,最近更新数据可认为设备最后所在平台
+    """
+    if isfullId == 1:
+        bigdata_res = requests.post("http://8.136.98.49:8002/search/equip", data={"device_id": d_id, "isfullId": "1"})
+        siqing_res = requests.post("http://www.yfzhwlw.com/search/equip", data={"device_id": d_id, "isfullId": "1"})
+    else:
+        bigdata_res = requests.post("http://8.136.98.49:8002/search/equip", data={"device_id": d_id})
+        siqing_res = requests.post("http://www.yfzhwlw.com/search/equip", data={"device_id": d_id})
+
+    django_data = json.loads(bigdata_res.content.decode()).get("data", [])
+    siqing_data = json.loads(siqing_res.content.decode()).get("data", [])
+    data = []
+    data.extend(django_data)
+    data.extend(siqing_data)
+
+    data = sorted(data, key=lambda e: e.__getitem__('uptime'), reverse=True)
+    data = sorted(data, key=lambda e: e.__getitem__('device_id'), reverse=True)
+    return data
+
+
+class Get_SIM_info(object):
+    """
+    自定义获取SIM卡对应卡商及数据
+    """
+
+    def __init__(self, iccid) -> None:
+        self.iccid = iccid
+        self.hz_status = {
+            0: "未知",
+            1: "测试期",
+            2: "沉默期",
+            3: "使用中",
+            4: "停机",
+            5: "停机保号",
+            6: "预销号",
+            7: "销号"
+        }
+        self.qp_status = {
+            "testing": "测试中",
+            "inventory": "库存",
+            "pending-activation": "待激活",
+            "activation": "已激活",
+            "deactivation": "已停卡",
+            "retired": "已销卡"
+        }
+
+    def hz_sim_info(self):
+        """获取合宙流量卡信息"""
+        url = "http://api.openluat.com/sim/iotcard/card"
+        payload = {
+            'iccid': self.iccid,
+        }
+        appkey = 'KDlhc9VY4rWSXkbM'
+        appsecret = 'DmwxcSB1b8dx7kLWqWMJNRLgyQhCvPJ7DHIfLdHIz9A18CifSHqJk3nWZ1vHv4cR'
+        auth = HTTPBasicAuth(appkey, appsecret)
+        try:
+            res = requests.post(url, json=payload, auth=auth, timeout=5)
+            data = json.loads(res.text)
+        except Exception as e:
+            data = {'code': 99999, 'msg': '接口调用异常异常'}
+        return data
+
+    def qp_sim_info(self):
+        """ 获取企鹏(SIMBOSS)流量卡信息 """
+        url = "https://api.simboss.com/2.0/device/detail"
+        current_milli_time = lambda: int(round(time.time() * 1000))
+        data_1 = "appid=%s&iccid=%s&timestamp=%s%s" % (
+            "102420177762", self.iccid, current_milli_time(), "6397d7e6a56589f1d93284e9800493e1")
+        sign = hashlib.sha256(data_1.encode('utf-8')).hexdigest()
+        data = {"appid": "102420177762", "iccid": self.iccid, "timestamp": current_milli_time(), "sign": sign}
+        try:
+            res = requests.post(url, data=data, timeout=5)
+            data = json.loads(res.text)
+        except Exception as e:
+            data = {'code': 99999, 'msg': '接口调用异常异常'}
+        return data
+
+    def get_sim_info(self):
+        """未知卡商情况下获取卡信息"""
+        hz_data = self.hz_sim_info()
+        if hz_data["code"] == 0:  # 合宙
+            sim_operators = 1
+            account_status = self.hz_status[hz_data["data"]["account_status"]]
+            if hz_data["data"]["active"] == 1:
+                active_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(hz_data["data"]["active_date"]))
+                data_plan = str(hz_data["data"]["data_plan"]) + "M"
+                data_usage = str(hz_data["data"]["data_usage"]) + "M"
+                data_balance = str(hz_data["data"]["data_balance"]) + "M"
+                expiry_date = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(hz_data["data"]["expiry_date"]))
+            else:
+                active_date = "未激活"
+                data_plan = "未激活"
+                data_usage = "未激活"
+                data_balance = "未激活"
+                expiry_date = "未激活"
+        else:
+            qp_data = self.qp_sim_info()
+            if qp_data["code"] == "0":
+                sim_operators = 2
+                account_status = self.qp_status[qp_data["data"]["status"]]
+                active_date = qp_data["data"].get("startDate", "")
+                if active_date:
+                    if qp_data["data"]["useCountAsVolume"] == False:
+                        data_plan = str(qp_data["data"]["totalDataVolume"]) + "M"
+                        data_usage = str(qp_data["data"]["usedDataVolume"]) + "M"
+                        data_balance = str(qp_data["data"]["totalDataVolume"] - qp_data["data"]["usedDataVolume"]) + "M"
+                    else:
+                        data_plan = str(qp_data["data"]["totalDataVolume"] * 1024) + "M"
+                        data_usage = str(qp_data["data"]["usedDataVolume"] * 1024) + "M"
+                        data_balance = str(
+                            (qp_data["data"]["totalDataVolume"] - qp_data["data"]["usedDataVolume"]) * 1024) + "M"
+                    expiry_date = qp_data["data"]["expireDate"]
+                else:
+                    data_plan = "未激活"
+                    data_usage = "未激活"
+                    data_balance = "未激活"
+                    expiry_date = "未激活"
+            else:
+                sim_operators = 3
+                account_status = "未知"
+                active_date = "未知"
+                data_plan = "未知"
+                data_usage = "未知"
+                data_balance = "未知"
+                expiry_date = "未知"
+        return sim_operators, account_status, active_date, data_plan, data_usage, data_balance, expiry_date