PYTHONではじめてのWEBサイトを作成 9
バインミー店のランキングの更新
全国のバインミー店をあらためてPlaces APIで取得する
毎月バインミー店の情報は更新されるのでデータベースの設計を変える
毎月ランキングも更新させたい
なのでまずはmodels.pyを更新する
modelsでmonthlydataモデルを作成
from banhmilove_app.models import Store, MonthlyData
from datetime import date
from django.core.management.base import BaseCommand
import requests
from banhmilove_app.models import Store, MonthlyData
from django.db import transaction
from datetime import date
class Command(BaseCommand):
help = 'Fetches Banh Mi shop data from Japan'
def handle(self, *args, **options):
self.stdout.write("Fetching Banh Mi shops in Japan...")
self.fetch_places()
def fetch_places(self):
locations = [
"Hokkaido", "Aomori", "Iwate", "Miyagi", "Akita", "Yamagata", "Fukushima",
"Ibaraki", "Tochigi", "Gunma", "Saitama", "Chiba", "Tokyo", "Kanagawa",
"Niigata", "Toyama", "Ishikawa", "Fukui", "Yamanashi", "Nagano", "Gifu",
"Shizuoka", "Aichi", "Mie", "Shiga", "Kyoto", "Osaka", "Hyogo", "Nara",
"Wakayama", "Tottori", "Shimane", "Okayama", "Hiroshima", "Yamaguchi",
"Tokushima", "Kagawa", "Ehime", "Kochi", "Fukuoka", "Saga", "Nagasaki",
"Kumamoto", "Oita", "Miyazaki", "Kagoshima", "Okinawa"
]
current_date = date.today()
for location in locations:
url = "https://maps.googleapis.com/maps/api/place/textsearch/json"
params = {
"query": f"Banh Mi shop in {location} Japan",
"key": "YOUR APP KEY", # 本番キーが公開されないように注意
"language": "ja"
}
response = requests.get(url, params=params)
self.stdout.write(f"Response from API: {response.text}") # APIの応答内容をログに出力
if response.status_code == 200:
results = response.json().get('results', [])
if not results:
self.stdout.write("No data received from API.")
else:
self.save_data(results, location, current_date)
self.stdout.write(f"Stores in {location} fetched and saved successfully.")
else:
self.stdout.write(f"Failed to fetch data for {location}: {response.status_code} - {response.text}")
def save_data(self, results, location, current_date):
with transaction.atomic():
for place in results:
city = self.fetch_place_details(place['place_id'])
store, created = Store.objects.get_or_create(
place_id=place.get('place_id'),
defaults={
'name': place.get('name'),
'prefecture': location,
'city': city if city else "N/A",
'url': place.get('website', ''),
'rating': place.get('rating', 0),
'review_count': place.get('user_ratings_total', 0),
'latitude': place.get('geometry', {}).get('location', {}).get('lat', 0),
'longitude': place.get('geometry', {}).get('location', {}).get('lng', 0)
}
)
if not created:
store.name = place.get('name')
store.prefecture = location
store.city = city if city else "N/A"
store.url = place.get('website', '')
store.rating = place.get('rating', 0)
store.review_count = place.get('user_ratings_total', 0)
store.latitude = place.get('geometry', {}).get('location', {}).get('lat', 0)
store.longitude = place.get('geometry', {}).get('location', {}).get('lng', 0)
store.save()
MonthlyData.objects.update_or_create(
date=current_date,
store=store,
defaults={
'ranking': 0, # ランキングは後で更新する
'weighted_score': store.weighted_score
}
)
print(f"Saved store: {store.name} with weighted score: {store.weighted_score}")
def fetch_place_details(self, place_id):
detail_url = "https://maps.googleapis.com/maps/api/place/details/json"
params = {
"place_id": place_id,
"fields": "address_component,website",
"key": "YOUR APP KEY", # 同様にAPIキーを安全に保管
"language": "ja"
}
response = requests.get(detail_url, params=params)
if response.status_code == 200:
details = response.json().get('result', {})
city = None
for component in details.get('address_components', []):
if 'locality' in component['types']:
city = component['long_name']
return city
return None
データの取得
python manage.py fetch_banhmi
取得できた
ついでにショップリストも修正
450店舗取得できたので、
store_list.htmlに50ショップ毎のページネーションを追加
都道府県も表示
都道府県で絞り込みできるように変更
レビュー数5が上位になってしまったので100以上お店だけに表示を調整
def national_ranking(request):
# レビュー数が100以上の店舗のみを取得し、weighted_scoreの降順で並び替え
national_stores = Store.objects.filter(review_count__gte=100).order_by('-weighted_score', '-review_count')[:20]
# ランキングの順位を付与
for idx, store in enumerate(national_stores):
store.rank = idx + 1
return render(request, 'banhmilove_app/rank.html', {'stores': national_stores})
Fetchで全国のバインミー店を再取得
6月のデータも取得
python manage.py fetch_banhmi
ついでにランキングページを修正
さらにVIEWSで毎月ランキング表示が変わるように修正
views.py
def national_ranking(request):
year = int(request.GET.get('year', timezone.now().year))
month = int(request.GET.get('month', timezone.now().month))
# 指定された年と月のデータを取得
monthly_data = MonthlyData.objects.filter(date__year=year, date__month=month, store__review_count__gte=100).order_by('-weighted_score', '-store__review_count')
# ランキングの順位を付与
for idx, data in enumerate(monthly_data):
data.ranking = idx + 1
# 1から12までの月のリストを生成
months = list(range(1, 13))
# データが存在するかをチェック
data_exists = monthly_data.exists()
return render(request, 'banhmilove_app/rank.html', {
'stores': monthly_data,
'year': year,
'month': month,
'months': months,
'data_exists': data_exists,
})
毎月表示が変わるようにテンプレートを修正
{% extends 'banhmilove_app/base.html' %}
{% block content %}
<div class="container">
<h1>{{ year }}年{{ month }}月バインミー店ランキング</h1>
<p>※スコアはレーティングとレビュー数から算出</p>
<!-- 月ごとのタブ -->
<ul class="nav nav-tabs" id="myTab" role="tablist">
{% for m in range(1, 13) %}
<li class="nav-item">
<a class="nav-link {% if m == month|int %}active{% endif %}" href="?year={{ year }}&month={{ m }}">{{ m }}月</a>
</li>
{% endfor %}
</ul>
<table class="table table-bordered ranking-table">
<thead class="thead-light">
<tr>
<th>順位</th>
<th>店名</th>
<th>所在地</th>
<th>スコア※</th>
<th>google<br>レーティング</th>
<th>google<br>レビュー数</th>
</tr>
</thead>
<tbody>
{% for data in stores %}
<tr>
<td class="index">{{ data.ranking }}</td>
<td>{{ data.store.name }}</td>
<td>{{ data.store.prefecture }}</td>
<td>{{ data.weighted_score|floatformat:2 }}</td>
<td>{{ data.store.rating }}</td>
<td>{{ data.store.review_count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
ランキングが月ごとに変わるように修正完了
今日はここまで
まとめ
5月目標を宣言して始めたけど6月の中盤になってしまった。
気にせずに前向きにいきましょう!
今回はランキングとDBを更新しました。
次はショップリストの更新と新ショップのページを作りましょう。
この記事が気に入ったらサポートをしてみませんか?