diff --git a/demo/index.html b/demo/index.html
index 7a5cf6e..e70f08d 100644
--- a/demo/index.html
+++ b/demo/index.html
@@ -6,6 +6,16 @@
新冠肺炎(2019-nCoV)疫情大屏
+
+
diff --git a/demo_proj/ncov/settings.py b/demo_proj/ncov/settings.py
index 0dc2b0b..c44f307 100644
--- a/demo_proj/ncov/settings.py
+++ b/demo_proj/ncov/settings.py
@@ -10,6 +10,9 @@
https://docs.djangoproject.com/en/2.2/ref/settings/
"""
+# insert project path here
+import sys; sys.path.insert(0, '..')
+
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
diff --git a/django_covid19/serializers.py b/django_covid19/serializers.py
index 3e2736d..8d5e1ca 100644
--- a/django_covid19/serializers.py
+++ b/django_covid19/serializers.py
@@ -167,6 +167,13 @@ class Meta:
exclude = ('id', 'dailyData')
+class StateDailyListSerializer(serializers.ModelSerializer):
+
+ class Meta:
+ model = models.State
+ fields = ['stateName', 'dailyData']
+
+
class StateDailySerializer(serializers.Serializer):
state = serializers.CharField()
diff --git a/django_covid19/urls.py b/django_covid19/urls.py
index 7efad3d..fd3e665 100644
--- a/django_covid19/urls.py
+++ b/django_covid19/urls.py
@@ -27,6 +27,7 @@
path('countries//daily/', views.CountryDailyListView.as_view(), name='country-daily-list'),
url(r'states/(?:(?Praw)/)?(?P[^/]+)/$', views.StateListView.as_view(), name='state-list'),
+ url(r'states/(?:(?Praw)/)?(?P[^/]+)/daily/$', views.StateListDailyListView.as_view(), name='state-list-daily-list'),
url(r'states/(?:(?Praw)/)?(?P[^/]+)/(?P[A-Z]+)/$', views.StateRetrieveView.as_view(), name='state-detail'),
url(r'states/(?:(?Praw)/)?(?P[^/]+)/(?P[A-Z]+)/daily/$', views.StateDailyListView.as_view(), name='state-daily-list'),
url(r'states/(?:(?Praw)/)?(?P[^/]+)/(?P[^/]+)/$', views.StateRetrieveByNameView.as_view(), name='state-detail-by-name'),
diff --git a/django_covid19/views.py b/django_covid19/views.py
index 7e3a378..7889a30 100644
--- a/django_covid19/views.py
+++ b/django_covid19/views.py
@@ -320,37 +320,14 @@ def get(self, request, countryShortCode, state, raw=None):
return Response(serializer.data)
-class StateDailyListView(APIView):
+class BaseDailyView(object):
- """州按天返回列表"""
-
- def get_object(self, countryShortCode, state):
- state = models.State.objects.filter(
- countryShortCode=countryShortCode, state=state).first()
- if state is None:
- raise Http404
- return state
-
- @method_decorator(cache_page(
- CACHE_PAGE_TIMEOUT, key_prefix='state-daily-list'))
- def get(self, request, countryShortCode, state, raw=None):
- inst = self.get_object(countryShortCode, state)
- result = inst.dailyData
- result = json.loads(result)
- if raw == 'raw':
- return Response(result)
- data = []
- for r in result:
- data.append(self.format(inst, r))
- serializer = serializers.StateDailySerializer(data, many=True)
- return Response(serializer.data)
-
- def format(self, inst, data):
+ def format(self, countryShortCode, stateName, data):
item = {}
item['date'] = data['date']
item['state'] = data['state']
- item['stateName'] = inst.stateName
- item['countryShortCode'] = inst.countryShortCode
+ item['stateName'] = stateName
+ item['countryShortCode'] = countryShortCode
item['confirmedCount'] = data.get('positive')
item['currentConfirmedCount'] = self.get_current_confirmed(data)
@@ -376,7 +353,34 @@ def get_current_confirmed_incr(self, data):
death = data['deathIncrease'] if data.get('deathIncrease') else 0
return positive - death
-class StateDailyListByNameView(StateDailyListView):
+
+class StateDailyListView(APIView, BaseDailyView):
+
+ """州按天返回列表"""
+
+ def get_object(self, countryShortCode, state):
+ state = models.State.objects.filter(
+ countryShortCode=countryShortCode, state=state).first()
+ if state is None:
+ raise Http404
+ return state
+
+ @method_decorator(cache_page(
+ CACHE_PAGE_TIMEOUT, key_prefix='state-daily-list'))
+ def get(self, request, countryShortCode, state, raw=None):
+ inst = self.get_object(countryShortCode, state)
+ result = inst.dailyData
+ result = json.loads(result)
+ if raw == 'raw':
+ return Response(result)
+ stateName = inst.stateName
+ data = []
+ for r in result:
+ data.append(self.format(countryShortCode, stateName, r))
+ serializer = serializers.StateDailySerializer(data, many=True)
+ return Response(serializer.data)
+
+class StateDailyListByNameView(APIView, BaseDailyView):
def get_object(self, countryShortCode, stateName):
state = models.State.objects.filter(
@@ -393,8 +397,54 @@ def get(self, request, countryShortCode, stateName, raw=None):
result = json.loads(result)
if raw == 'raw':
return Response(result)
+ stateName = inst.stateName
data = []
for r in result:
- data.append(self.format(inst, r))
+ data.append(self.format(countryShortCode, stateName, r))
serializer = serializers.StateDailySerializer(data, many=True)
- return Response(serializer.data)
\ No newline at end of file
+ return Response(serializer.data)
+
+
+class StateListDailyListView(ListAPIView, BaseDailyView):
+
+ serializer_class = serializers.StateDailyListSerializer
+ filter_class = filters.StateFilter
+
+ def get_queryset(self):
+ countryShortCode = self.kwargs['countryShortCode']
+ return models.State.objects.filter(
+ countryShortCode=countryShortCode).order_by('state')
+
+ def list(self, request, *args, **kwargs):
+ countryShortCode = kwargs['countryShortCode']
+ queryset = self.filter_queryset(self.get_queryset())
+
+ if kwargs.get('raw') == 'raw':
+ self.serializer_class = serializers.StateRawSerializer
+
+ result = []
+ page = self.paginate_queryset(queryset)
+ if page is not None:
+ serializer = self.get_serializer(page, many=True)
+ for item in serializer.data:
+ stateName = item['stateName']
+ dailyData = json.loads(item['dailyData'])
+ for daily in dailyData:
+ result.append(
+ self.format(countryShortCode, stateName, daily))
+ return self.get_paginated_response(result)
+
+ serializer = self.get_serializer(queryset, many=True)
+ for item in serializer.data:
+ stateName = item['stateName']
+ dailyData = json.loads(item['dailyData'])
+ for daily in dailyData:
+ result.append(
+ self.format(countryShortCode, stateName, daily))
+ return Response(result)
+
+ @method_decorator(cache_page(
+ CACHE_PAGE_TIMEOUT, key_prefix='state-list-daily-list'))
+ def dispatch(self, *args, **kwargs):
+ return super(StateListDailyListView, self).dispatch(*args, **kwargs)
+
diff --git a/docs/README.md b/docs/README.md
index ffae0a8..2af20d3 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -783,6 +783,76 @@ http://111.231.75.86:8000/api/states/USA/?stateNames=Alaska,Alabama
]
```
+
+#### 多个州的日统计 :id=state-USA-list-daily
+
+可获取全部州或某几个州的日统计数据列表;
+
+接口地址:/api/states/USA/\/daily/
+
+原始数据:/api/states/raw/USA/\/daily/
+
+请求方法:GET
+
+请求参数:
+
+参数 | 描述
+------------------- | -------
+stateNames | 州名,如:Alaska,Alabama;以逗号分割多个值;大小写敏感;
+states | 州缩写,如:AK(Alaska),AL(Alabama);大小写敏感;
+
+示例链接:
+
+http://111.231.75.86:8000/api/states/USA/daily/
+
+http://111.231.75.86:8000/api/states/USA/daily/?states=AK,AL
+
+http://111.231.75.86:8000/api/states/USA/daily/?stateNames=Alaska,Alabama
+
+返回结果:
+
+```
+[
+ {
+ "date": 20200306,
+ "state": "AK",
+ "stateName": "Alaska",
+ "countryShortCode": "USA",
+ "confirmedCount": 0,
+ "currentConfirmedCount": 0,
+ "suspectedCount": 1,
+ "curedCount": null,
+ "deadCount": 0,
+ "currentConfirmedIncr": 0,
+ "confirmedIncr": null,
+ "suspectedIncr": null,
+ "curedIncr": null,
+ "deadIncr": null
+ },
+ // (20200307 - 现在)AK 日统计
+ ...
+ {
+ "date": 20200307,
+ "state": "AL",
+ "stateName": "Alabama",
+ "countryShortCode": "USA",
+ "confirmedCount": 0,
+ "currentConfirmedCount": 0,
+ "suspectedCount": null,
+ "curedCount": null,
+ "deadCount": null,
+ "currentConfirmedIncr": 0,
+ "confirmedIncr": null,
+ "suspectedIncr": null,
+ "curedIncr": null,
+ "deadIncr": null
+ },
+ // (20200307 - 现在)AL 日统计
+ ...
+ // 其他州的日统计
+```
+
+
#### 某州最新疫情 :id=state-USA-detail
diff --git a/setup.cfg b/setup.cfg
index 8304969..ed9d8d3 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
[metadata]
name = django_covid19
-version = 0.4a0
+version = 0.4a1
description = An django app of the covid-19 API in countries around the world, provinces and cities in China, and states in the USA.
long_description = file: README.md
long-description-content-type = text/markdown