-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from thinkAmi/feature/migrate-to-django2
Python3.7.2 & Django 2.1.5 対応
- Loading branch information
Showing
57 changed files
with
1,400 additions
and
418 deletions.
There are no files selected for viewing
Empty file.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class ApiConfig(AppConfig): | ||
name = 'apps.api' |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
""" とりあえず正常系のテストだけ:異常系は起こらないはず... """ | ||
|
||
from datetime import datetime | ||
|
||
import pytest | ||
import pytz | ||
|
||
from apps.tweets.tests.factories import TweetsFactory | ||
|
||
|
||
@pytest.fixture | ||
def total_apples_expected(): | ||
for i in range(3): | ||
TweetsFactory(name='フジ') | ||
for i in range(2): | ||
TweetsFactory(name='シナノドルチェ') | ||
for i in range(5): | ||
TweetsFactory(name='シナノゴールド') | ||
|
||
return '''[ | ||
{ | ||
"name": "シナノドルチェ", | ||
"y": 2, | ||
"color": "AntiqueWhite" | ||
}, | ||
{ | ||
"name": "シナノゴールド", | ||
"y": 5, | ||
"color": "Gold" | ||
}, | ||
{ | ||
"name": "フジ", | ||
"y": 3, | ||
"color": "Red" | ||
} | ||
]''' | ||
|
||
|
||
@pytest.mark.django_db(transaction=True) | ||
class TestTotalApples: | ||
""" total_apples() のテスト """ | ||
|
||
def test_get(self, client, total_apples_expected): | ||
actual = client.get('/api/v1/total/') | ||
assert actual.content.decode('utf-8') == total_apples_expected | ||
|
||
|
||
@pytest.fixture | ||
def total_apples_by_month_expected(): | ||
for i in range(1, 4): | ||
# RuntimeWarningを避けるため、tzinfoを渡す | ||
# RuntimeWarning: | ||
# DateTimeField Tweets.tweeted_at received a naive datetime (2019-01-10 00:00:00) | ||
# while time zone support is active. | ||
TweetsFactory(name='フジ', | ||
tweeted_at=datetime(2019, i, 10, tzinfo=pytz.timezone("Asia/Tokyo"))) | ||
for i in range(1, 3): | ||
TweetsFactory(name='シナノドルチェ', | ||
tweeted_at=datetime(2019, i, 10, tzinfo=pytz.timezone("Asia/Tokyo"))) | ||
for i in range(1, 6): | ||
TweetsFactory(name='シナノゴールド', | ||
tweeted_at=datetime(2019, i, 10, tzinfo=pytz.timezone("Asia/Tokyo"))) | ||
|
||
return '''[ | ||
{ | ||
"name": "フジ", | ||
"data": [ | ||
1, | ||
1, | ||
1, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0 | ||
], | ||
"color": "Red" | ||
}, | ||
{ | ||
"name": "シナノゴールド", | ||
"data": [ | ||
1, | ||
1, | ||
1, | ||
1, | ||
1, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0 | ||
], | ||
"color": "Gold" | ||
}, | ||
{ | ||
"name": "シナノドルチェ", | ||
"data": [ | ||
1, | ||
1, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0, | ||
0 | ||
], | ||
"color": "AntiqueWhite" | ||
} | ||
]''' | ||
|
||
|
||
@pytest.mark.django_db(transaction=True) | ||
class TestTotalApplesByMonth: | ||
""" total_apples_by_month()のテスト """ | ||
|
||
def test_get(self, client, total_apples_by_month_expected): | ||
actual = client.get('/api/v1/month/') | ||
assert actual.content.decode('utf-8') == total_apples_by_month_expected |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,9 @@ | ||
from django.conf.urls import patterns, url | ||
from apps.api import views | ||
from django.urls import path | ||
|
||
urlpatterns = patterns('', | ||
url(r'^v1/total/$', views.total_apples), | ||
url(r'^v1/month/$', views.total_apples_by_month), | ||
) | ||
app_name = 'api' | ||
|
||
urlpatterns = [ | ||
path('v1/total/', views.TotalApplesView.as_view(), name='total'), | ||
path('v1/month/', views.TotalApplesByMonthView.as_view(), name='total_by_month'), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,62 +1,76 @@ | ||
from django.http import HttpResponse | ||
from django.db import models | ||
import json | ||
from collections import OrderedDict | ||
from django.http import JsonResponse | ||
from django.views import View | ||
|
||
from apps.cultivar.apple import Apple | ||
from apps.tweets.models import Tweets | ||
from libs.cultivars import Apple | ||
|
||
def render_json_response(request, data, status=None): | ||
'''responseをJSONで返す''' | ||
json_str = json.dumps(data, ensure_ascii=False, indent=2) | ||
response = HttpResponse(json_str, content_type='application/json; charset=utf-8', status=status) | ||
return response | ||
|
||
|
||
def total_apples(request): | ||
'''リンゴの品種別合計数量を返す''' | ||
results = [] | ||
apples = Apple() | ||
|
||
# valuesで取得したい項目、annotateで別途集計したい項目をそれぞれ取得できる | ||
for tweet in Tweets.objects.values('name').annotate(quantity=models.Count('name')): | ||
|
||
apple_dict = OrderedDict([ | ||
('name', tweet['name']), | ||
('quantity', tweet['quantity']), | ||
('color', apples.get_color(tweet['name'])) | ||
]) | ||
results.append(apple_dict) | ||
|
||
return render_json_response(request, results) | ||
|
||
|
||
def total_apples_by_month(request): | ||
'''リンゴの月別品種別合計数量を返す''' | ||
results = [] | ||
apples = Apple() | ||
tweets = Tweets.objects.extra(select={ 'month': "date_part('month', tweeted_at)::int" }) \ | ||
.values('name', 'month').annotate(quantity=models.Count('name')).order_by('name', 'month') | ||
|
||
# DBで縦持ちしているものをHighchartsのために横持ちにする | ||
name = tweets[0]['name'] | ||
quantities = [0] * 12 | ||
|
||
for tweet in tweets: | ||
if name != tweet['name']: | ||
results.append(OrderedDict([ | ||
('name', name), | ||
('quantity', quantities), | ||
('color', apples.get_color(name)) | ||
])) | ||
|
||
name = tweet['name'] | ||
quantities = [0] * 12 | ||
|
||
quantities[tweet['month'] - 1] = tweet['quantity'] | ||
|
||
results.append(OrderedDict([ | ||
('name', name), | ||
('quantity', quantities), | ||
('color', apples.get_color(name)) | ||
])) | ||
return render_json_response(request, results) | ||
|
||
|
||
class RingoJsonResponse(JsonResponse): | ||
""" ringo-tabetter用設定を行ったJsonResponseオブジェクト(薄いラッパー) """ | ||
|
||
def __init__(self, data): | ||
""" | ||
:param data: JSON化するデータ | ||
""" | ||
super().__init__(data=data, | ||
safe=False, | ||
json_dumps_params={'ensure_ascii': False, 'indent': 2}) | ||
|
||
|
||
# ------------- | ||
# Highcharts用 | ||
# ------------- | ||
|
||
class TotalApplesView(View): | ||
""" リンゴの品種別合計数量を返すView """ | ||
|
||
http_method_names = ["get"] | ||
|
||
def get(self, request, *args, **kwargs) -> RingoJsonResponse: | ||
results = [] | ||
apples = Apple() | ||
|
||
for tweet in Tweets.calculate_total_by_name().all(): | ||
apple_dict = dict( | ||
name=tweet['name'], | ||
y=tweet['quantity'], | ||
color=apples.get_color(tweet['name']), | ||
) | ||
results.append(apple_dict) | ||
return RingoJsonResponse(results) | ||
|
||
|
||
class TotalApplesByMonthView(View): | ||
""" リンゴの月別品種別合計数量を返すView """ | ||
|
||
http_method_names = ["get"] | ||
|
||
def get(self, request, *args, **kwargs) -> RingoJsonResponse: | ||
results = [] | ||
apples = Apple() | ||
tweets = Tweets.calculate_total_by_name_and_month() | ||
|
||
# DBで縦持ちしているものをHighchartsのために横持ちにする | ||
name = tweets[0]['name'] | ||
quantities = [0] * 12 | ||
|
||
for tweet in tweets: | ||
if name != tweet['name']: | ||
results.append({ | ||
'name': name, | ||
'data': quantities, | ||
'color': apples.get_color(name), | ||
}) | ||
|
||
name = tweet['name'] | ||
quantities = [0] * 12 | ||
|
||
quantities[tweet['month'] - 1] = tweet['quantity'] | ||
|
||
results.append({ | ||
'name': name, | ||
'data': quantities, | ||
'color': apples.get_color(name), | ||
}) | ||
return RingoJsonResponse(results) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import os | ||
import yaml | ||
from django.conf import settings | ||
|
||
|
||
class Apple: | ||
def __init__(self): | ||
self.cultivars = self.load_cultivars() | ||
|
||
def load_cultivars(self) -> dict: | ||
""" プロジェクト直下にあるapples.yamlから品種名を取得する """ | ||
with open(os.path.join(settings.BASE_DIR, 'apples.yaml'), 'r', encoding='utf-8') as f: | ||
cultivars = yaml.load(f) | ||
return cultivars | ||
|
||
def get_color(self, cultivar: str) -> str: | ||
""" 品種名に紐づく色名を取得する """ | ||
result = [x for x in self.cultivars if x['Name'] == cultivar] | ||
# 基本的に重複は無い前提 | ||
return result[0]['Color'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class CultivarConfig(AppConfig): | ||
name = 'apps.cultivar' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import pytest | ||
|
||
|
||
class TestApple: | ||
""" Appleクラスのテスト """ | ||
|
||
def test_get_color_品種が存在する場合(self): | ||
from apps.cultivar.apple import Apple | ||
|
||
sut = Apple() | ||
sut.cultivars = [ | ||
{'Name': 'シナノゴールド', 'Color': 'Gold'}, | ||
{'Name': 'シナノドルチェ', 'Color': 'Red'}, | ||
{'Name': '王林', 'Color': 'Yellow'}, | ||
] | ||
|
||
actual = sut.get_color('シナノゴールド') | ||
assert actual == 'Gold' | ||
|
||
def test_get_color_品種が存在しない場合(self): | ||
from apps.cultivar.apple import Apple | ||
|
||
sut = Apple() | ||
sut.cultivars = [ | ||
{'Name': 'シナノゴールド', 'Color': 'Gold'}, | ||
{'Name': 'シナノドルチェ', 'Color': 'Red'}, | ||
{'Name': '王林', 'Color': 'Yellow'}, | ||
] | ||
|
||
with pytest.raises(IndexError): | ||
sut.get_color('フジ') |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.apps import AppConfig | ||
|
||
|
||
class HighChartsConfig(AppConfig): | ||
name = 'apps.highcharts' |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.