PYTHONではじめてのWEBサイトを作成 10
Python DjangoではじめてWEBサイトを作る。
はや1ヶ月が経過しました。
頑張っていきましょう
今日は全国バインミーのストアリストを最新に更新
そのためにmodels.pyを修正してfecthファイルで新しくデータを取得しなおします。
Let's Start
全国バインミーのストアリストを最新する準備
model.py を更新
registered_date = models.DateField() # 登録月
を挿入
class Store(models.Model):
name = models.CharField(max_length=255) # 店名
prefecture = models.CharField(max_length=100) # 都道府県
city = models.CharField(max_length=100) # 市区町村
website = models.URLField(blank=True, null=True)
url = models.URLField() # URL
rating = models.FloatField() # レーティング
review_count = models.IntegerField() # レビュー数
latitude = models.FloatField() # 緯度
longitude = models.FloatField() # 経度
place_id = models.CharField(max_length=255, unique=True) # Google Place ID
weighted_score = models.FloatField(null=True, blank=True) # 加重スコア
registered_date = models.DateField() # 取得日
registered_month = models.CharField(max_length=7, default='2024-01') # 取得月 (YYYY-MM形式)
python manage.py makemigrations
python manage.py migrate
データを削除してから取得しなおし
banhmilove_app/management/commands/delete_all_stores.py
from django.core.management.base import BaseCommand
from banhmilove_app.models import Store
class Command(BaseCommand):
help = 'Delete all existing store data'
def handle(self, *args, **options):
Store.objects.all().delete()
self.stdout.write(self.style.SUCCESS('Successfully deleted all store data'))
python manage.py delete_all_stores
一旦データを削除しました。
データ取得のスクリプト修正
取得月のデータ
取得日のデータ
都道府県名を日本語で表示する辞書を追加
import datetime
from django.core.management.base import BaseCommand
import requests
from banhmilove_app.models import Store, MonthlyData
from django.db import transaction
class Command(BaseCommand):
help = 'Fetches Banh Mi shop data from Japan'
PREFECTURE_MAPPING = {
"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": "沖縄県"
}
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 = datetime.date.today()
current_month = current_date.strftime("%Y-%m")
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_GOOGLE_API_KEY", # 本番キーが公開されないように注意
"language": "ja"
}
response = requests.get(url, params=params)
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, current_month)
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, current_month):
with transaction.atomic():
for place in results:
city = self.fetch_place_details(place['place_id'])
prefecture_jp = self.PREFECTURE_MAPPING.get(location, location)
store, created = Store.objects.get_or_create(
place_id=place.get('place_id'),
defaults={
'name': place.get('name'),
'prefecture': prefecture_jp,
'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),
'registered_date': current_date,
'registered_month': current_month
}
)
if not created:
store.name = place.get('name')
store.prefecture = prefecture_jp
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.registered_date = current_date
store.registered_month = current_month
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 registered date: {store.registered_date}")
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_GOOGLE_API_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
今月オープンしたストアリストの表示
def new_store(request):
current_month = timezone.now().month
current_year = timezone.now().year
new_stores = Store.objects.filter(registered_date__year=current_year, registered_date__month=current_month)
return render(request, 'banhmilove_app/new_store.html', {
'new_stores': new_stores,
})
ストアリストに登録月のカラムを追加し、5月にあって6月にない店舗を「閉鎖」として表示するための手順を示します。
新規オープンストアの表示
new_store.html
{% extends 'banhmilove_app/base.html' %}
{% block content %}
<div class="container">
<h1>今月オープンしたバインミー店</h1>
{% if new_stores %}
<table class="table table-bordered ranking-table">
<thead class="thead-light">
<tr>
<th>店名</th>
<th>所在地</th>
<th>登録月</th>
<th>google<br>レーティング</th>
<th>google<br>レビュー数</th>
</tr>
</thead>
<tbody>
{% for store in new_stores %}
<tr>
<td>{{ store.name }}</td>
<td>{{ store.prefecture }}</td>
<td>{{ store.registered_date }}</td>
<td>{{ store.rating }}</td>
<td>{{ store.review_count }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>今月オープンしたバインミー店はありません。</p>
{% endif %}
</div>
{% endblock %}
ストアリストのビューも修正
ストアリストのビューを修正して、5月と6月のデータを適切に取得し、重複を排除し、閉鎖店舗を識別するようにします。
from django.core.paginator import Paginator
from django.shortcuts import render
from .models import Store
def store_list(request):
prefecture = request.GET.get('prefecture')
name_query = request.GET.get('name')
# 5月のストアを取得
may_stores = Store.objects.filter(registered_date__year=2024, registered_date__month=5)
# 6月のストアを取得
june_stores = Store.objects.filter(registered_date__year=2024, registered_date__month=6)
# 6月のストアIDリスト
june_store_ids = june_stores.values_list('id', flat=True)
# 閉鎖した店舗リスト
closed_stores = may_stores.exclude(id__in=june_store_ids)
# 5月と6月のストアリストをマージ
stores = june_stores.union(may_stores).order_by('registered_date')
# 検索フィルタ
if prefecture:
stores = stores.filter(prefecture=prefecture)
if name_query:
stores = stores.filter(name__icontains=name_query)
paginator = Paginator(stores, 50) # 1ページに表示する店舗数を50に設定
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
prefectures = Store.objects.values_list('prefecture', flat=True).distinct()
return render(request, 'banhmilove_app/store_list.html', {
'page_obj': page_obj,
'prefecture': prefecture,
'name_query': name_query,
'prefectures': prefectures,
'closed_stores': closed_stores,
})
store_list.htmlの更新
{% extends 'banhmilove_app/base.html' %}
{% block content %}
<div class="container">
<h1>Store List</h1>
<!-- 検索フォーム -->
<form method="get" action="{% url 'store_list' %}" class="form-inline mb-3">
<div class="form-group mr-2">
<label for="name" class="mr-2">店舗名:</label>
<input type="text" name="name" id="name" value="{{ name_query }}" class="form-control" placeholder="店舗名を入力">
</div>
<div class="form-group mr-2">
<label for="prefecture">都道府県:</label>
<select name="prefecture" id="prefecture" class="form-control">
<option value="">All</option>
{% for pref in prefectures %}
<option value="{{ pref }}" {% if pref == prefecture %}selected{% endif %}>{{ pref }}</option>
{% endfor %}
</select>
</div>
<button type="submit" class="btn btn-primary mt-2">Search</button>
</form>
<table class="ranking-table mt-3">
<thead>
<tr>
<th>店名</th>
<th>都道府県</th>
<th>市区町村</th>
<th>google<br>レーティング</th>
<th>google<br>レビュー数</th>
<th>Website</th>
<th>登録月</th>
</tr>
</thead>
<tbody>
{% for store in page_obj %}
<tr>
<td>{{ store.name }}</td>
<td>{{ store.prefecture }}</td>
<td>{{ store.city }}</td>
<td>{{ store.rating }}</td>
<td>{{ store.review_count }}</td>
<td><a href="{{ store.url }}" target="_blank">Visit Website</a></td>
<td>{{ store.registered_date|date:"Y年m月" }}</td>
</tr>
{% empty %}
<tr>
<td colspan="7">No stores found.</td>
</tr>
{% endfor %}
<!-- 閉鎖した店舗 -->
{% for store in closed_stores %}
<tr>
<td>{{ store.name }}</td>
<td>{{ store.prefecture }}</td>
<td>{{ store.city }}</td>
<td>閉鎖</td>
<td>閉鎖</td>
<td>閉鎖</td>
<td>{{ store.registered_date|date:"Y年m月" }} (閉鎖)</td>
</tr>
{% endfor %}
</tbody>
</table>
<!-- ページネーション -->
<nav aria-label="Page navigation example" class="mt-4">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% if prefecture %}&prefecture={{ prefecture }}{% endif %}" aria-label="Previous">
<span aria-hidden="true">«</span>
</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
<li class="page-item {% if page_obj.number == num %}active{% endif %}">
<a class="page-link" href="?page={{ num }}{% if prefecture %}&prefecture={{ prefecture }}{% endif %}">{{ num }}</a>
</li>
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% if prefecture %}&prefecture={{ prefecture }}{% endif %}" aria-label="Next">
<span aria-hidden="true">»</span>
</a>
</li>
{% endif %}
</ul>
</nav>
</div>
{% endblock %}
まとめ
だいぶ間が空いてしまいましたが、今回はデータを再取得してショップリストを表示しました!
続いて分析ページに入ります。
この記事が気に入ったらサポートをしてみませんか?