Skip to content

Commit

Permalink
Merge pull request #1 from thinkAmi/feature/migrate-to-django2
Browse files Browse the repository at this point in the history
Python3.7.2 & Django 2.1.5 対応
  • Loading branch information
thinkAmi committed Feb 14, 2019
2 parents 7ce4bd7 + 9bd2ea6 commit 56e0793
Show file tree
Hide file tree
Showing 57 changed files with 1,400 additions and 418 deletions.
Empty file added apps/__init__.py
Empty file.
3 changes: 0 additions & 3 deletions apps/api/admin.py

This file was deleted.

5 changes: 5 additions & 0 deletions apps/api/apps.py
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'
3 changes: 0 additions & 3 deletions apps/api/models.py

This file was deleted.

3 changes: 0 additions & 3 deletions apps/api/tests.py

This file was deleted.

Empty file added apps/api/tests/__init__.py
Empty file.
128 changes: 128 additions & 0 deletions apps/api/tests/test_views.py
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
12 changes: 7 additions & 5 deletions apps/api/urls.py
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'),
]
136 changes: 75 additions & 61 deletions apps/api/views.py
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 added apps/cultivar/__init__.py
Empty file.
20 changes: 20 additions & 0 deletions apps/cultivar/apple.py
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']
5 changes: 5 additions & 0 deletions apps/cultivar/apps.py
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'
31 changes: 31 additions & 0 deletions apps/cultivar/tests/test_cultivars.py
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('フジ')
3 changes: 0 additions & 3 deletions apps/highcharts/admin.py

This file was deleted.

5 changes: 5 additions & 0 deletions apps/highcharts/apps.py
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'
3 changes: 0 additions & 3 deletions apps/highcharts/models.py

This file was deleted.

0 comments on commit 56e0793

Please sign in to comment.