1

I´m trying to create a MP3 validator for an File Field. The validator receives the file_path as a parameter and performs all the necessary logic to validate the mp3 file.

My problem is that I´m not able to give the function the entire path when the validator is called. When I print the file_name variable I just get the file´s name and not the entire path.

Can anyone tell me how can I acces the file´s full path using the models.FileField() ?

Validator:

from django.forms import ValidationError

def isMp3Valid(file_path):
    print (file_path)
    is_valid = False

    f = open(file_path, 'r')
    block = f.read(1024)
    frame_start = block.find(chr(255))
    block_count = 0 #abort after 64k
    while len(block)>0 and frame_start == -1 and block_count<64:
        block = f.read(1024)
        frame_start = block.find(chr(255))
        block_count+=1

    if frame_start > -1:
        frame_hdr = block[frame_start:frame_start+4]
        is_valid = frame_hdr[0] == chr(255)

        mpeg_version = ''
        layer_desc = ''
        uses_crc = False
        bitrate = 0
        sample_rate = 0
        padding = False
        frame_length = 0

        if is_valid:
            is_valid = ord(frame_hdr[1]) & 0xe0 == 0xe0 #validate the rest of the frame_sync bits exist

        if is_valid:
            if ord(frame_hdr[1]) & 0x18 == 0:
                mpeg_version = '2.5'
            elif ord(frame_hdr[1]) & 0x18 == 0x10:
                mpeg_version = '2'
            elif ord(frame_hdr[1]) & 0x18 == 0x18:
                mpeg_version = '1'
            else:
                is_valid = False

        if is_valid:
            if ord(frame_hdr[1]) & 6 == 2:
                layer_desc = 'Layer III'
            elif ord(frame_hdr[1]) & 6 == 4:
                layer_desc = 'Layer II'
            elif ord(frame_hdr[1]) & 6 == 6:
                layer_desc = 'Layer I'
            else:
                is_valid = False

        if is_valid:
            uses_crc = ord(frame_hdr[1]) & 1 == 0

            bitrate_chart = [
                [0,0,0,0,0],
                [32,32,32,32,8],
                [64,48,40,48,16],
                [96,56,48,56,24],
                [128,64,56,64,32],
                [160,80,64,80,40],
                [192,96,80,96,40],
                [224,112,96,112,56],
                [256,128,112,128,64],
                [288,160,128,144,80],
                [320,192,160,160,96],
                [352,224,192,176,112],
                [384,256,224,192,128],
                [416,320,256,224,144],
                [448,384,320,256,160]]
            bitrate_index = ord(frame_hdr[2]) >> 4
            if bitrate_index==15:
                is_valid=False
            else:
                bitrate_col = 0
                if mpeg_version == '1':
                    if layer_desc == 'Layer I':
                        bitrate_col = 0
                    elif layer_desc == 'Layer II':
                        bitrate_col = 1
                    else:
                        bitrate_col = 2
                else:
                    if layer_desc == 'Layer I':
                        bitrate_col = 3
                    else:
                        bitrate_col = 4
                bitrate = bitrate_chart[bitrate_index][bitrate_col]
                is_valid = bitrate > 0

        if is_valid:
            sample_rate_chart = [
                [44100, 22050, 11025],
                [48000, 24000, 12000],
                [32000, 16000, 8000]]
            sample_rate_index = (ord(frame_hdr[2]) & 0xc) >> 2
            if sample_rate_index != 3:
                sample_rate_col = 0
                if mpeg_version == '1':
                    sample_rate_col = 0
                elif mpeg_version == '2':
                    sample_rate_col = 1
                else:
                    sample_rate_col = 2
                sample_rate = sample_rate_chart[sample_rate_index][sample_rate_col]
            else:
                is_valid = False

        if is_valid:
            padding = ord(frame_hdr[2]) & 1 == 1

            padding_length = 0
            if layer_desc == 'Layer I':
                if padding:
                    padding_length = 4
                frame_length = (12 * bitrate * 1000 / sample_rate + padding_length) * 4
            else:
                if padding:
                    padding_length = 1
                frame_length = 144 * bitrate * 1000 / sample_rate + padding_length
            is_valid = frame_length > 0

            # Verify the next frame
            if(frame_start + frame_length < len(block)):
                is_valid = block[frame_start + frame_length] == chr(255)
            else:
                offset = (frame_start + frame_length) - len(block)
                block = f.read(1024)
                if len(block) > offset:
                    is_valid = block[offset] == chr(255)
                else:
                    is_valid = False

    f.close()
    if not is_valid:
        raise ValidationError(_("El archivo no es formato MP3"))
    return is_valid

Model:

from django.utils.translation import ugettext as _
from django.db import models
from music_manager.extra import isMp3Valid

class Cancion(models.Model):
    nombre = models.CharField(max_length=100,verbose_name=_("nombre"))
    audio_file = models.FileField(upload_to="/static/audio", verbose_name=_("audio"),validators=[isMp3Valid])

    class Meta:
        verbose_name_plural= "Canciones"
        verbose_name = "Cancion"
    # Override the __unicode__() method to return out something meaningful!
    def __unicode__(self):
        return self.nombre
Pablo Estrada
  • 3,182
  • 4
  • 30
  • 74
  • Possible duplicate of http://stackoverflow.com/questions/1211527/django-getting-the-absolute-path-of-a-filefield – avenet Sep 28 '15 at 19:42

1 Answers1

2

Django calls your validator with the value of audio_file. So your isMp3Valid-Validator method receives an instance of django.db.models.fields.files.FieldFile. This class has an attribute called file, which is an django.core.files.base.File.

And the File class has an attribute called name. The value of name should be the absolute path of your audio_file.

Your validator should be changed like this:

def is_mp3_valid(audio_file):
    file_path = audio_file.file.name
    is_valid = False

    f = open(file_path, 'r')
    .... (snip) ...

I hope this helps you.

Amir Hadi
  • 308
  • 2
  • 9
  • Sorry, you did not mention the Django version you are using. My should answer is valid for Django 1.6 and later. – Amir Hadi Sep 28 '15 at 19:50
  • Thanks for the answer. I´m using django 1.8 right now, is there anything important that I should change in this version? – Pablo Estrada Sep 28 '15 at 19:51
  • I tested this with Django 1.8. By testing I mean that I checked that the absolute file path is given to your function. – Amir Hadi Sep 28 '15 at 20:08