diff --git a/README.md b/README.md index 97fd164..386d558 100644 --- a/README.md +++ b/README.md @@ -9,14 +9,15 @@   2. Backend API - -REST or GraphQL - - Flask (Python): Lightweight and easy to set up, suitable for small to medium projects. - Django (Python): A more comprehensive framework that includes an ORM and admin panel out-of-the-box. - - Express (Node.js): A fast and minimalistic web framework for Node.js. - - Ruby on Rails (Ruby): A powerful and mature full-stack web framework. -  + - Django REST Framework +  -3. Frontend +3. Backend DB + -Initially SQL lite, but it quickly met its limitations when trying to scrape data for 30 teams at once. It could not handle all the simulataneous connections. + - PostgreSQL is the new DB. + +4. Frontend - React/Redux - D3.js - Chart.js @@ -24,7 +25,7 @@ - Websockets or Server-Sent Events   -4. Deploy +1. Deploy diff --git a/nba_data/management/commands/delete_player_data.py b/nba_data/management/commands/delete_player_data.py new file mode 100644 index 0000000..ece6719 --- /dev/null +++ b/nba_data/management/commands/delete_player_data.py @@ -0,0 +1,12 @@ +from django.core.management.base import BaseCommand +from nba_data.models import PlayerData + +class Command(BaseCommand): + # Provides a description for use with the custom django management command (python manage.py help). + help = 'Delete all player data' + + def handle(self, *args, **options): + # Delete all player data + PlayerData.objects.all().delete() + + self.stdout.write(self.style.SUCCESS('Successfully deleted all players in DB')) \ No newline at end of file diff --git a/nba_data/management/commands/delete_player_data_and_reset_id.py b/nba_data/management/commands/delete_player_data_and_reset_id.py new file mode 100644 index 0000000..10b2bbf --- /dev/null +++ b/nba_data/management/commands/delete_player_data_and_reset_id.py @@ -0,0 +1,17 @@ +from django.core.management.base import BaseCommand +from nba_data.models import PlayerData +from django.db import connection + +class Command(BaseCommand): + # Provides a description for use with the custom django management command (python manage.py help). + help = 'Delete all player data and reset primary key sequence in DB' + + def handle(self, *args, **options): + # Delete all player data + PlayerData.objects.all().delete() + + # Reset the PK sequence + with connection.cursor() as cursor: + cursor.execute('ALTER SEQUENCE nba_data_playerdata_id_seq RESTART WITH 1;') + + self.stdout.write(self.style.SUCCESS('Successfully deleted all players in DB')) \ No newline at end of file diff --git a/nba_data/scraper.py b/nba_data/scraper.py index 2d510b6..34bc4dd 100644 --- a/nba_data/scraper.py +++ b/nba_data/scraper.py @@ -32,7 +32,8 @@ for team in teams: if table is None: print(f"Table not found for team {team} and season {season}.") - sys.exit(1) + # sys.exit(1) + continue header_row = table.find("thead").find("tr") rows = table.find("tbody").find_all("tr") @@ -55,17 +56,17 @@ for team in teams: # locate current directory script_dir = os.path.dirname(os.path.abspath(__file__)) - + # CSV file - csv_output_path = os.path.join(script_dir, '..', 'data', 'output.csv') + csv_output_path = os.path.join(script_dir, '..', 'data', f'{team}_{season}_output.csv') with open(csv_output_path, "w", newline="") as csvfile: - writer = csv.DictWriter(csvfile, fieldnames =headers) + writer = csv.DictWriter(csvfile, fieldnames=headers) writer.writeheader() for row in data: writer.writerow(row) # Save as JSON - json_output_path = os.path.join(script_dir, '..', 'data', 'output.json') + json_output_path = os.path.join(script_dir, '..', 'data', f'{team}_{season}_output.json') with open(json_output_path, 'w') as jsonfile: json.dump(data, jsonfile) @@ -102,4 +103,7 @@ for team in teams: team=row['team'], season=row['season'], ) - player_data.save() \ No newline at end of file + player_data.save() + + + \ No newline at end of file diff --git a/nba_data/serializers.py b/nba_data/serializers.py new file mode 100644 index 0000000..88634de --- /dev/null +++ b/nba_data/serializers.py @@ -0,0 +1,8 @@ +# Serializers are defined that will convert model instances to JSON +from rest_framework import serializers +from .models import PlayerData + +class PlayerDataSerializer(serializers.ModelSerializer): + class Meta: + model = PlayerData + fields = '__all__' diff --git a/nba_data/urls.py b/nba_data/urls.py index 100434e..dbdf7fc 100644 --- a/nba_data/urls.py +++ b/nba_data/urls.py @@ -1,6 +1,10 @@ from django.urls import path -from .views import get_player_data +from .views import PlayerDataList, PlayerDataByTeamList, PlayerDataBySeasonList, PlayerDataByNameList, TopScorersbySeasonList urlpatterns = [ - path('api/player_data/', get_player_data, name='player_data') + path('api/playerdata/', PlayerDataList.as_view(), name='playerdata_list'), + path('api/playerdata/team//', PlayerDataByTeamList.as_view(), name='playerdata_by_team'), + path('api/playerdata/season//', PlayerDataBySeasonList.as_view(), name='playerdata_by_season'), + path('api/playerdata/name//', PlayerDataByNameList.as_view(), name='playerdata_by_name'), + path('api/playerdata/topscorers/season//', TopScorersbySeasonList.as_view(), name='top_scorers_by_season'), ] \ No newline at end of file diff --git a/nba_data/views.py b/nba_data/views.py index 10f8362..921f7a1 100644 --- a/nba_data/views.py +++ b/nba_data/views.py @@ -2,9 +2,51 @@ from django.shortcuts import render from django.http import JsonResponse from django.core import serializers from .models import PlayerData +from rest_framework import generics +from .serializers import PlayerDataSerializer + # Create your views here. -def get_player_data(request): - data = serializers.serialize('json', PlayerData.objects.all()) - return JsonResponse(data, safe=False) \ No newline at end of file +# API view to list all PlayerData instances +class PlayerDataList(generics.ListCreateAPIView): + queryset = PlayerData.objects.all().order_by('id') + serializer_class = PlayerDataSerializer + # pagination_class = None + + +# Fetch player data by team +class PlayerDataByTeamList(generics.ListAPIView): + serializer_class = PlayerDataSerializer + + def get_queryset(self): + team = self.kwargs['team'] + return PlayerData.objects.filter(team=team) + + +# Fetch player data by season +class PlayerDataBySeasonList(generics.ListAPIView): + serializer_class = PlayerDataSerializer + + def get_queryset(self): + season = self.kwargs['season'] + return PlayerData.objects.filter(season=season) + + +# Fetch player data by player name +class PlayerDataByNameList(generics.ListAPIView): + serializer_class = PlayerDataSerializer + + def get_queryset(self): + name = self.kwargs['name'] + return PlayerData.objects.filter(name__icontains=name) + + +# Fetch Top 20 players by PTS DESC for the season specified. +class TopScorersbySeasonList(generics.ListAPIView): + serializer_class = PlayerDataSerializer + + def get_queryset(self): + season = self.kwargs['season'] + return PlayerData.objects.filter(season=season).order_by('-PTS')[:20] + diff --git a/nba_stats/settings.py b/nba_stats/settings.py index 077df56..82a83cf 100644 --- a/nba_stats/settings.py +++ b/nba_stats/settings.py @@ -34,7 +34,7 @@ SECRET_KEY = SECRET_DJANGO # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['*'] # Application definition @@ -43,6 +43,8 @@ INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'nba_data', + 'corsheaders', + 'rest_framework', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', @@ -50,6 +52,7 @@ INSTALLED_APPS = [ ] MIDDLEWARE = [ + 'corsheaders.middleware.CorsMiddleware', 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', @@ -135,3 +138,14 @@ STATIC_URL = 'static/' # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +REST_FRAMEWORK = { + 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', + 'PAGE_SIZE': 100, # Adjust this value according to the number of records you want to display per page +} + +CORS_ALLOWED_ORIGINS = [ + "http://localhost:5173", # Replace this with the origin of your frontend app +] + + diff --git a/nba_stats/urls.py b/nba_stats/urls.py index 970cf52..a31a966 100644 --- a/nba_stats/urls.py +++ b/nba_stats/urls.py @@ -18,6 +18,6 @@ from django.contrib import admin from django.urls import path, include urlpatterns = [ - path('', include('nba_data.urls')), path('admin/', admin.site.urls), + path('', include('nba_data.urls')), ]