Open In App

Music Player using Django

Last Updated : 06 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we’ll build a Music Player using Django. To get started, the first thing we’ll do is create an account, just like with other music players. After creating the account, we’ll log in. Once successfully logged in, we’ll be redirected to the home page. On the home page, we can search for songs based on our preferences we used an API to fetch songs. Additionally, we’ll have the option to add songs, and the corresponding pictures related to those songs will be displayed on the home page. We can easily play the songs and manage the login system through the admin panel.

Music Player using Django

Below is the step-by-step guide to playing music player

To install Django follow these steps.

Starting the Project Folder

To start the project use this command

django-admin startproject music_player_project
cd core

we create two apps for creating the app use this command

python manage.py startapp api
python manage.py startapp music_player_app

Now add this app to the ‘settings.py’

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"music_player_app",
"api",
"rest_framework"
]

File Structure

file

Setting Necessary Files

api/models.py :Below,code defines a Django model named “Song” with fields for id, title, category, artist, audio file, and audio image, along with their respective properties, and a string representation method returning the song title.

Python3




# api/models.py
from django.db import models
 
class Song(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=100)
    categorie = models.CharField(max_length=100, null=True, default=None)
    artist = models.CharField(max_length=100)
    audio_file = models.FileField(upload_to='audio/')
    audio_img = models.FileField(upload_to='audio_img/')
 
    def __str__(self):
        return self.title


music_player_app/models.py : below code defines a custom Django user model named “CustomUser” that extends the AbstractUser model, adding fields for groups and user permissions, allowing users to be associated with multiple groups and permissions.

Python3




# music_player_app/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
 
class CustomUser(AbstractUser):
    groups = models.ManyToManyField(
        'auth.Group',
        related_name='customuser_set',
        related_query_name='user'
    )
    user_permissions = models.ManyToManyField(
        'auth.Permission',
        related_name='customuser_set',
        related_query_name='user'
    )


api/views.py : below code defines two Django Rest Framework views, “SongListCreateView” for handling the listing and creation of songs, and “SongDetailView” for handling the retrieval, update, and deletion of individual songs, using the “Song” model and its corresponding serializer “SongSerializer.”

Python3




# api/views.py
from rest_framework import generics
from .models import Song
from .serializers import SongSerializer
 
class SongListCreateView(generics.ListCreateAPIView):
    queryset = Song.objects.all()
    serializer_class = SongSerializer
 
class SongDetailView(generics.RetrieveUpdateDestroyAPIView):
    queryset = Song.objects.all()
    serializer_class = SongSerializer


music_player_app/views.py : below code defines Django views for user registration, login, and authenticated user actions such as viewing the home page, adding a song, and updating a song. It uses forms for registration and login, and requires authentication for certain actions.

Python3




# music_player_app/views.py
from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect
from django.contrib.auth import login
from .forms import RegistrationForm, LoginForm
 
def register(request):
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            user = form.save()
            login(request, user)
            return redirect('home')
    else:
        form = RegistrationForm()
    return render(request, 'music_player_app/register.html', {'form': form})
 
def user_login(request):
    if request.method == 'POST':
        form = LoginForm(request, request.POST)
        if form.is_valid():
            user = form.get_user()
            login(request, user)
            return redirect('home')
    else:
        form = LoginForm()
    return render(request, 'music_player_app/login.html', {'form': form})
 
@login_required
def index(request):
    return render(request, 'music_player_app/index.html')
 
@login_required
def AddSong(request):
    return render(request, 'music_player_app/AddSong.html')
 
@login_required
def UpdateSong(request, pk):
    return render(request, 'music_player_app/UpdateSong.html')


api/serializers.py : below code defines a Django Rest Framework serializer, “SongSerializer,” using the model “Song” and including all fields for serialization.

Python3




# api/serializers.py
from rest_framework import serializers
from .models import Song
 
class SongSerializer(serializers.ModelSerializer):
    class Meta:
        model = Song
        fields = '__all__'


music_palyer_app/forms.py : below code defines a registration form (“RegistrationForm”) and a login form (“LoginForm”) for a custom user model, extending default Django forms for user creation and authentication.

Python3




# music_player_app/forms.py
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from .models import CustomUser
 
class RegistrationForm(UserCreationForm):
    class Meta:
        model = CustomUser
        fields = ['username', 'password1', 'password2']
 
class LoginForm(AuthenticationForm):
    class Meta:
        model = CustomUser
        fields = ['username', 'password']


api/urls.py : below code sets up Django URL patterns for song listing/creation and song detail using “SongListCreateView” and “SongDetailView” views, respectively.

Python3




# api/urls.py
from django.urls import path
from .views import SongListCreateView, SongDetailView
 
urlpatterns = [
    path(' ', SongListCreateView.as_view(), name='song-list-create'),
    path('songs/<int:pk>/', SongDetailView.as_view(), name='song-detail'),
]


music_player_app/urls.py : below code defines Django URL patterns for user authentication, registration, login, logout, and views for the home page, updating a song, and adding a song in the music player app. It includes paths for default authentication views, custom registration and login views, and specific URLs for app features.

Python3




# music_player_app/urls.py
from django.contrib import admin
from django.urls import path, include
from django.contrib.auth.views import LogoutView
from music_player_app.views import register, user_login
from music_player_app.views import index, UpdateSong, AddSong
 
urlpatterns = [
    path('accounts/', include('django.contrib.auth.urls')),
    path('register/', register, name='register'),
    path('login/', user_login, name='login'),
    path('logout/', LogoutView.as_view(next_page='/login/'), name='logout'),
    path('home', index, name='home'),
    path('UpdateSong/<int:pk>', UpdateSong, name='UpdateSong'),
    path('AddSong', AddSong, name='AddSong'),
]


Creating GUI

templates/music_player_app/html Files

AddSong.html : The HTML document presents a form for adding a song to a music player app, styled with Bootstrap. JavaScript functions validate the form, collect input data, and send a POST request to a Django API endpoint for song addition, with CSRF token handling.

HTML




<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Add Song</title>
 
    <!-- Bootstrap CSS -->
          integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
          crossorigin="anonymous" />
  </head>
  <body>
    <div class="container mt-5">
      <h2>Add Song</h2>
 
      <form id="songForm">
        <div class="form-group">
          <label for="title">Title:</label>
          <input type="text" class="form-control" id="title" name="title" required />
          <div class="invalid-feedback">Title is required.</div>
        </div>
 
        <div class="form-group">
          <label for="artist">Artist:</label>
          <input type="text" class="form-control" id="artist" name="artist" required />
          <div class="invalid-feedback">Artist is required.</div>
        </div>
        <div class="form-group">
          <label for="categorie">Categorie:</label>
          <input type="text" class="form-control" id="categorie" name="categorie" required />
          <div class="invalid-feedback">Categorie is required.</div>
        </div>
 
        <div class="form-group">
          <label for="audio_file">Audio File:</label>
          <input type="file" class="form-control-file" id="audio_file" name="audio_file"
                 accept="audio/*" required />
          <div class="invalid-feedback">Audio file is required.</div>
        </div>
        <div class="form-group">
          <label for="audio_img">Audio Img:</label>
          <input type="file" class="form-control-file" id="audio_img" name="audio_img" required />
          <div class="invalid-feedback">Audio Img is required.</div>
        </div>
 
        <button type="button" class="btn btn-primary" onclick="postData()">Submit</button>
      </form>
    </div>
 
    <!-- Bootstrap JS and dependencies -->
            integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
            crossorigin="anonymous"></script>
            integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
            crossorigin="anonymous"></script>
            integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
            crossorigin="anonymous"></script>
 
    <script>
      function postData() {
        // Validate the form
        if (validateForm()) {
          let title = document.getElementById('title').value
          let artist = document.getElementById('artist').value
          let categorie = document.getElementById('categorie').value
          let audio_file = document.getElementById('audio_file').files[0]
          let audio_img = document.getElementById('audio_img').files[0]
       
          const formData = new FormData()
          formData.append('title', title)
          formData.append('artist', artist)
          formData.append('categorie', categorie)
          formData.append('audio_file', audio_file)
          formData.append('audio_img', audio_img)
       
          fetch('http://127.0.0.1:8000/api/songs/', {
            method: 'POST',
            headers: {
              'X-CSRFToken': getCookie('csrftoken')
            },
            body: formData
          })
            .then((response) => response.json())
            .then((result) => {
              console.log('Success:', result)
              // Refresh the page after successful submission
              location.reload()
            })
            .catch((error) => {
              // Handle errors as needed
              console.error('Error:', error)
            })
        }
      }
       
      function validateForm() {
        const title = document.getElementById('title').value
        const artist = document.getElementById('artist').value
        const categorie = document.getElementById('categorie').value
        const audio_file = document.getElementById('audio_file').files[0]
        const audio_img = document.getElementById('audio_img').files[0]
        const invalidFeedbacks = document.querySelectorAll('.invalid-feedback')
        invalidFeedbacks.forEach((element) => {
          element.style.display = 'none'
        })
       
        let isValid = true
       
        if (!title.trim()) {
          document.getElementById('title').nextElementSibling.style.display = 'block'
          isValid = false
        }
        if (!categorie.trim()) {
          document.getElementById('categorie').nextElementSibling.style.display = 'block'
          isValid = false
        }
       
        if (!artist.trim()) {
          document.getElementById('artist').nextElementSibling.style.display = 'block'
          isValid = false
        }
       
        if (!audio_file) {
          document.getElementById('audio_file').nextElementSibling.style.display = 'block'
          isValid = false
        }
        if (!audio_img) {
          document.getElementById('audio_img').nextElementSibling.style.display = 'block'
          isValid = false
        }
       
        return isValid
      }
       
      // Function to get CSRF token from cookies
      function getCookie(name) {
        var cookieValue = null
        if (document.cookie && document.cookie !== '') {
          var cookies = document.cookie.split(';')
          for (var i = 0; i < cookies.length; i++) {
            var cookie = cookies[i].trim()
            if (cookie.substring(0, name.length + 1) === name + '=') {
              cookieValue = decodeURIComponent(cookie.substring(name.length + 1))
              break
            }
          }
        }
        return cookieValue
      }
    </script>
  </body>
</html>


index.html : The HTML document implements a music player interface using Bootstrap, featuring an audio player, playlist, search bar, and buttons for song management. JavaScript functions handle song retrieval, playback, deletion, and redirection to add/update songs. A search function interacts with the Saavn API to display results, and there’s a logout function.

HTML




<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Music Player</title>
    <style>
      body {
        font-family: 'Arial', sans-serif;
        text-align: center;
        margin: 50px;
      }
      #audioPlayer {
        width: 100%;
        max-width: 400px;
        margin: 20px auto;
      }
      #playlist {
        list-style: none;
        padding: 0;
      }
      #playlist li {
        margin: 5px;
        cursor: pointer;
        transition: transform 0.3s ease-in-out;
        display: flex;
        justify-content: space-between;
        align-items: center;
      }
      #playlist li:hover {
        transform: scale(1.1);
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="player">
        <img style="width:250px; height:250px;"
             alt id="audioPlayerimg" />
        <br />
        <audio id="audioPlayer" class="w-100" controls>Your browser does not support the audio element.</audio>
      </div>
      <label for="Search">Search Song:</label>
      <input type="text" id="Search"  placeholder="Enter song name" />
      <button onclick="SearchSongs()">Search</button>
      <ul id="playlist" class="list-group"></ul>
      <button type="button" class="btn btn-primary mt-3" data-toggle="modal" data-target="#addSongModal"
              onclick="AddSong()">Add Song</button>
      <button type="button" class="btnlogout btn btn-danger mt-3" data-toggle="modal"
              data-target="#addSongModal" onclick="Logout()">Logout</button>
    </div>
    <script>
       
document.addEventListener('DOMContentLoaded', function () {
  fetchSongs();
});
 
const audioPlayer = document.getElementById('audioPlayer');
const audioPlayerimg = document.getElementById('audioPlayerimg');
const playlist = document.getElementById('playlist');
 
function fetchSongs() {
  fetch('/api/songs/')
      .then(response => response.json())
      .then(songs => {
          songs.forEach(song => {
              playlist.innerHTML += `<li class="list-group-item" onclick="playSong('${song.audio_file}','${song.audio_img}')">
              <span>${song.title} - ${song.artist}-${song.categorie}</span>
              <div>
                <button class="btn btn-info btn-sm" onclick="UpdateSong(${song.id})">Update</button>
                <button class="btn btn-danger btn-sm" onclick="deleteSong(${song.id})">Delete</button>
              </div></li>`;
          });
      })
      .catch(error => console.error('Error fetching data:', error));
}
 
function playSong(songSrc, songimg) {
  console.log(songSrc);
  console.log(songimg);
  document.querySelectorAll('#playlist li').forEach((item) => {
      item.style.transform = 'scale(1)';
  });
  event.target.style.transform = 'scale(1.2)';
  audioPlayer.src = songSrc;
  console.log(audioPlayerimg);
  audioPlayerimg.src = songimg;
  audioPlayer.play();
}
 
function deleteSong(songId) {
  if (confirm('Are you sure you want to delete this song?')) {
      fetch(`/api/songs/${songId}/`, {
          method: 'DELETE',
          headers: {
              'Content-Type': 'application/json',
              'X-CSRFToken': '{{ csrf_token }}',
          },
      })
          .then(response => {
              if (response.ok) {
                  location.reload();
              } else {
                  alert('Failed to delete the song. Please try again.');
              }
          })
          .catch(error => {
              console.error('Error:', error);
          });
  }
}
 
function AddSong() {
  window.location.href = `/AddSong`;
}
 
function UpdateSong(itemId) {
  window.location.href = `/UpdateSong/${itemId}`;
}
 
function Logout(itemId) {
  window.location.href = `/logout/`;
}
function SearchSongs() {
  const SearchSong = document.getElementById('Search').value.toLowerCase();
  // Saavn API endpoint for searching songs
  const saavnSearchUrl = 'https://saavn.me/search/songs';
 
  // Query parameters for the search
  const params = {
      query: SearchSong,
  };
 
  // Request headers
  const headers = {
      'Content-Type': 'application/json',
  };
 
  // Make the GET request to search for songs
  fetch(`${saavnSearchUrl}?${new URLSearchParams(params)}`, {
      method: 'GET',
      headers: headers,
  })
      .then(response => response.json())
      .then(songData => {
          playlist.innerHTML = '';
          for (const song of songData.data.results) {
              const songName = song.name;
              const artistName = song.primaryArtists;
              const highestQualityDownloadUrl = song.downloadUrl.find(downloadUrl => downloadUrl.quality === '320kbps');
              const image150x150 = song.image.find(image => image.quality === '150x150');
              const lowestQualityImage = song.image.find(image => image.quality === '50x50');
              playlist.innerHTML += `<li class="list-group-item" onclick="playSong('${highestQualityDownloadUrl.link}','${image150x150.link}')"><span>
            <img src="${lowestQualityImage.link}">
            ${songName} by ${artistName}</span>
            </li>`;
          }
      })
      .catch(error => console.error('Error:', error));
 
}
    </script>
  </body>
</html>


login.html : The HTML document presents a login form using Bootstrap styling, with a title, input fields for username and password, and a login button. It includes a link to register for an account if the user doesn’t have one. The form is submitted via POST request and includes a CSRF token for security.

HTML




<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Login</title>
</head>
<body>
  <div class="container">
    <div class="row">
      <div class="col-md-6 offset-md-3">
        <h2 class="mt-4 mb-4">Login</h2>
        <form method="post" class="mb-4">
          {% csrf_token %}
          {{ form.as_p }}
          <button type="submit" class="btn btn-primary">Login</button>
        </form>
        <p>Don't have an account? <a href="{% url 'register' %}" class="btn btn-link">Register here</a>.</p>
      </div>
    </div>
  </div>
</body>
</html>


register.html : The HTML document displays a registration form using Bootstrap styling, including fields for username, password, and password confirmation. The form is submitted via POST request and contains a CSRF token for security. Additionally, there’s a link to the login page for users who already have an account.

HTML




<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Register</title>
  </head>
  <body>
    <div class="container">
      <div class="row">
        <div class="col-md-6 offset-md-3">
          <h2 class="mt-4 mb-4">Register</h2>
          <form method="post" class="mb-4">
            {% csrf_token %}
            {{ form.as_p }}
            <button type="submit" class="btn btn-primary">Register</button>
          </form>
          <p>Already have an account? <a href="{% url 'login' %}" class="btn btn-link">Login here</a>.</p>
        </div>
      </div>
    </div>
  </body>
</html>


UpdateSong.html : The HTML document is an update form for a song in a music player app, utilizing Bootstrap. JavaScript fetches existing song data, populates the form fields, and handles form submission with an API call for updating. CSRF token is included, and upon success, the user is redirected to the home page.

HTML




<!-- music_player_app/templates/music_player_app/update_form.html -->
 
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Update Song</title>
  </head>
  <body>
    <div class="container mt-5">
      <h2>Update Song</h2>
      <form id="updateForm">
        <div class="form-group">
          <label for="title">Title</label>
          <input type="text" class="form-control" id="title" name="title" required />
          <label for="artist">Artist</label>
          <input type="text" class="form-control" id="artist" name="artist" required />
          <label for="categorie">Categorie</label>
          <input type="text" class="form-control" id="categorie" name="categorie" required />
          <label for="audio_file">Audio File</label>
          <input type="file" class="form-control-file" id="audio_file" name="audio_file" accept="audio/*" required />
          <label for="audio_img">Audio Img</label>
          <input type="file" class="form-control-file" id="audio_img" name="audio_img" required />
        </div>
        <!-- Add other form fields as needed -->
 
        <button type="submit" class="btn btn-primary">Update</button>
      </form>
    </div>
 
    <script>
      document.addEventListener('DOMContentLoaded', function () {
        // Fetch song data and fill the form fields
        const url = window.location.pathname.split('/')
        let songId = url[2]
        fetch(`/api/songs/${songId}/`)
          .then((response) => response.json())
          .then((data) => {
            document.getElementById('title').value = data.title
            document.getElementById('artist').value = data.artist
            document.getElementById('categorie').value = data.categorie
            document.getElementById('audio_file').value = ''
            document.getElementById('audio_img').value = ''
          })
          .catch((error) => console.error('Error fetching song data:', error))
       
        // Submit form with API call
        document.getElementById('updateForm').addEventListener('submit', function (event) {
          event.preventDefault()
       
          // Get form data
          const formData = new FormData(this)
       
          // Make API call to update song
          fetch(`/api/songs/${songId}/`, {
            method: 'PUT',
            headers: {
              'X-CSRFToken': getCookie('csrftoken') // Ensure to include CSRF token
            },
            body: formData
          })
            .then((response) => response.json())
            .then((data) => {
              alert('Song updated successfully!')
              window.location.href = '/home' // Redirect to the song list page
            })
            .catch((error) => console.error('Error updating song:', error))
        })
      })
       
      // Function to get CSRF token from cookies
      function getCookie(name) {
        var cookieValue = null
        if (document.cookie && document.cookie !== '') {
          var cookies = document.cookie.split(';')
          for (var i = 0; i < cookies.length; i++) {
            var cookie = cookies[i].trim()
            if (cookie.substring(0, name.length + 1) === name + '=') {
              cookieValue = decodeURIComponent(cookie.substring(name.length + 1))
              break
            }
          }
        }
        return cookieValue
      }
    </script>
  </body>
</html>


api/admin.py : here we register the models of api app.

Python3




from django.contrib import admin
from .models import Song
 
class SongAdmin(admin.ModelAdmin):
    list_display = ('id','title','categorie', 'artist', )
    search_fields = ('title', 'artist')
 
admin.site.register(Song, SongAdmin)


music_player_app/admin.py : here , we register the app of music_player_app app.

Python3




# music_player_app/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import CustomUser
 
admin.site.register(CustomUser, UserAdmin)


Deployement of the Project

Run these commands to apply the migrations:

python3 manage.py makemigrations
python3 manage.py migrate

Run the server with the help of following command:

python3 manage.py runserver

Output

login

register

song-home-page-

Video Demonstration



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads