Why am I getting an error stating unsupported file when I've specified I want to use .mp3

I’m trying to make a music player with Django and Postgresql, I’ve created a song model that is working in the database except when I try to upload an audio file with a .mp3 extension. Does anyone know how to fix this issue? Thanks

model.py:

from django.db import models
    from django.contrib.auth.models import User
    from cloudinary.models import CloudinaryField
    from recordroomapp.helper import get_audio_length
    from .validators import validate_is_audio


    class Artist(models.Model):
        artist = models.CharField(max_length=100, unique=True)
        slug = models.SlugField(max_length=100, unique=True)
        created_on = models.DateTimeField(auto_now_add=True)

        def __str__(self):
            return self.artist
class Song(models.Model):
        title = models.CharField(max_length=100, unique=False)
        slug = models.SlugField(max_length=100, unique=True)
        song = models.FileField(
            upload_to='media/', validators=[validate_is_audio], null=True)
        song_length = models.DecimalField(
             blank=True, max_digits=10, decimal_places=2, null=True)
        songinfo = models.ForeignKey(
            "Artist", on_delete=models.CASCADE, related_name='song_post', null=True)
        updated_on = models.DateTimeField(auto_now=True)
      # featured_image = CloudinaryField('image', default='placeholder')
        created_on = models.DateTimeField(auto_now_add=True)
        likes = models.ManyToManyField(User, related_name='song_likes', blank=True)

        class Meta:
            ordering = ['-created_on']

        def __str__(self):
            return self.title

        # def __init__(self):
        #     return self.song_length

        def save(self, *args, **kwargs):
            if not self.song_length:
                 audio_length = get_audio_length(self.song)
                self.song_length = f'{audio_length:.2f}'

            return super().save(*args, **kwargs)

        def number_of_likes(self):
            return self.likes.count()
class Comment(models.Model):
        post = models.ForeignKey(
            Song, on_delete=models.CASCADE, related_name='comments')
        name = models.CharField(max_length=100)
        email = models.EmailField()
        body = models.TextField()
        created_on = models.DateTimeField(auto_now_add=True)
        approved = models.BooleanField(default=False)

        class Meta:
            ordering = ['created_on']

        def __str__(self):
             return f"Comment {self.body} by {self.name}"

views.py:

from django.shortcuts import render, get_object_or_404, HttpResponse
    from django.views import generic, View
    from .models import Song


    class SongList(generic.ListView):
        model = Song
        queryset = Song.objects.order_by('-created_on')
        template_name = 'index.html'


    class SongDetail(View):

        def get(self, request, slug, *args, **kwargs):
            queryset = Song.objects.all()
            post = get_object_or_404(queryset, slug=slug)
            comments = post.comments.filter(approved=True).order_by('-created_on')
            liked = False
            if post.likes.filter(id=self.request.user.id).exists():
                liked = True

            return render(
                request,
                "song_detail.html",
                {
                    "song": queryset,
                    "post": post,
                    "comments": comments,
                    "liked": liked
                },
            )

admin.py:

from django.contrib import admin
    from .models import Artist, Song, Comment
    from django_summernote.admin import SummernoteModelAdmin


    @admin.register(Artist)
    class ArtistAdmin(SummernoteModelAdmin):
        list_display = ('artist', 'slug', 'created_on')
        search_fields = ['artist']


    @admin.register(Song)
    class SongAdmin(SummernoteModelAdmin):
        prepopulated_fields = {'slug': ('title',)}
        list_filter = ['created_on']
        summernote_fields = ('content')
        list_display = ('title', 'slug', 'song', 'created_on')
        search_fields = ['title', 'content']

validators.py:

import os
    from django.core.exceptions import ValidationError
    from mutagen.mp3 import MP3


    def validate_is_audio(file):

        try:
            audio = MP3(file)

            if not audio:
                raise TypeError()

            first_file_check = True

        except Exception as e:
            first_file_check = False

        if not first_file_check:
            raise ValidationError('Unsupported file type.')
        valid_file_extensions = ('.mp3',)
        ext = os.path.splitext(file.name)[1]
        if ext.lower() not in valid_file_extensions:
            raise ValidationError('Unacceptable file extension.')

helper.py:

from mutagen.mp3 import MP3


    def get_audio_length(file):
        audio = MP3(file)
        return audio.info.length

If I had to debug something like this, the first thing I’d try would be to add print calls in validate_is_audio to print file, file.name and os.path.splitext(file.name) to see what is happening here.

It might be the dot in your validator string. But as said in the previous reply debug that part to see what is going on with the extension validation.

I’ve changed validate_is_audio to:

def validate_is_audio(file):
    try:
        audio = MP3(file)
        print(file)
        if not audio:
            raise TypeError()
    except Exception as e:
        print(e)
        raise ValidationError('Unsupported file type')

I’m not getting a location for the file in the terminal when I run it either. Thanks for replying too

How are you uploading files into your models, are you using the Admin for that?

yep, I’m trying to add the songs as the admin