From de93bd7b0ad4ca486e3c355dd22ff13e70651712 Mon Sep 17 00:00:00 2001 From: Kevin Mok Date: Sun, 24 Jun 2018 02:30:19 -0400 Subject: [PATCH] Store counts for genres in Genre model Have not assigned most common genre to Track models yet (currently blank). --- recreate-db.txt | 8 ++++++++ requirements.txt | 2 +- spotifyvis/models.py | 17 +++++++++++++++-- spotifyvis/utils.py | 35 +++++++++++++++++++++++++++++------ 4 files changed, 53 insertions(+), 9 deletions(-) create mode 100644 recreate-db.txt diff --git a/recreate-db.txt b/recreate-db.txt new file mode 100644 index 0000000..5c1e574 --- /dev/null +++ b/recreate-db.txt @@ -0,0 +1,8 @@ +# https://stackoverflow.com/a/34576062/8811872 + +sudo su postgres +psql +drop database spotifyvis; +create database spotifyvis with owner django; +\q +exit diff --git a/requirements.txt b/requirements.txt index 7eba139..59c9dc6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ idna==2.6 isort==4.3.4 lazy-object-proxy==1.3.1 mccabe==0.6.1 -psycopg2==2.7.4 +psycopg2-binary==2.7.4 pylint==1.8.4 pytz==2018.4 requests==2.18.4 diff --git a/spotifyvis/models.py b/spotifyvis/models.py index 99f93d8..398647e 100644 --- a/spotifyvis/models.py +++ b/spotifyvis/models.py @@ -35,6 +35,18 @@ class User(models.Model): # }}} User # +class Genre(models.Model): + + class Meta: + verbose_name = "Genre" + verbose_name_plural = "Genres" + + name = models.CharField(primary_key=True, max_length=50) + num_songs = models.PositiveIntegerField() + + def __str__(self): + return self.name + # Track {{{ # class Track(models.Model): @@ -51,7 +63,9 @@ class Track(models.Model): runtime = models.PositiveSmallIntegerField() name = models.CharField(max_length=200) users = models.ManyToManyField(User, blank=True) - genre = models.CharField(max_length=30) + # genre = models.CharField(max_length=30) + genre = models.ForeignKey(Genre, on_delete=models.CASCADE, blank=True, + null=True) def __str__(self): return self.name @@ -60,7 +74,6 @@ class Track(models.Model): # AudioFeatures {{{ # - class AudioFeatures(models.Model): class Meta: diff --git a/spotifyvis/utils.py b/spotifyvis/utils.py index 7898141..e4dc4ec 100644 --- a/spotifyvis/utils.py +++ b/spotifyvis/utils.py @@ -3,8 +3,8 @@ import requests import math import pprint -from .models import Artist, User, Track, AudioFeatures -from django.db.models import Count, Q +from .models import * +from django.db.models import Count, Q, F from django.http import JsonResponse from django.core import serializers import json @@ -13,7 +13,6 @@ import json # parse_library {{{ # - def parse_library(headers, tracks, user): """Scans user's library for certain number of tracks to update library_stats with. @@ -48,6 +47,8 @@ def parse_library(headers, tracks, user): artist_id=artist_dict['id'], name=artist_dict['name'], ) + if artist_created: + tally_artist_genres(headers, artist_dict['id']) # update_artist_genre(headers, artist_obj) # get_or_create() returns a tuple (obj, created) @@ -59,8 +60,8 @@ def parse_library(headers, tracks, user): track_artists, top_genre, user) # if a new track is not created, the associated audio feature does not need to be created again - if track_created: - save_audio_features(headers, track_dict['track']['id'], track_obj) + # if track_created: + save_audio_features(headers, track_dict['track']['id'], track_obj) """ TODO: Put this logic in another function # Audio analysis could be empty if not present in Spotify database @@ -100,7 +101,7 @@ def save_track_obj(track_dict, artists, top_genre, user): popularity=int(track_dict['popularity']), runtime=int(float(track_dict['duration_ms']) / 1000), name=track_dict['name'], - genre=top_genre, + # genre=top_genre, ) # have to add artists and user after saving object since track needs to @@ -126,6 +127,8 @@ def save_audio_features(headers, track_id, track): """ response = requests.get("https://api.spotify.com/v1/audio-features/{}".format(track_id), headers = headers).json() + if track_id is '5S1IUPueD0xE0vj4zU3nSf': + pprint.pprint(response) if 'error' in response: return @@ -330,6 +333,7 @@ def get_top_genre(headers, top_artist_id): """ artist_response = requests.get('https://api.spotify.com/v1/artists/' + top_artist_id, headers=headers).json() + # pprint.pprint(artist_response) if len(artist_response['genres']) > 0: return artist_response['genres'][0] else: @@ -337,6 +341,25 @@ def get_top_genre(headers, top_artist_id): # }}} # +def tally_artist_genres(headers, artist_id): + """Tallies up genres for artist for the respective Genre models. Should be + called when new Artist object is created. + + :headers: For making the API call. + :artist_id: Artist ID for which to tally up genres for. + + :returns: None + + """ + artist_response = requests.get('https://api.spotify.com/v1/artists/' + + artist_id, headers=headers).json() + for genre in artist_response['genres']: + genre_obj, created = Genre.objects.get_or_create(name=genre, + defaults={'num_songs':1}) + if not created: + genre_obj.num_songs = F('num_songs') +1 + genre_obj.save() + # process_library_stats {{{ # def process_library_stats(library_stats):