Search code examples
file-uploadflaskflask-restfulwerkzeugflask-restplus

AttributeError: 'NoneType' object has no attribute 'filename'. Flask-Restplus doesn't seem to recognize uploaded file as Filestorage object


I am trying to upload 2 files(an audio and image file) along with some data. I am very new to using Flask, but after reviewing other people with Filestorage issues, I am not sure what I am doing wrong.

class FiguresResource(Resource):
    parser = reqparse.RequestParser()
    parser.add_argument(
        'thing',
        type=str)
    parser.add_argument(
        'image_file',
        type=werkzeug.datastructures.FileStorage,
        location=UPLOAD_FOLDER)
    parser.add_argument(
        'audio_file',
        type=werkzeug.datastructures.FileStorage,
        location=UPLOAD_FOLDER)

    def post(self):
        db = connect(MONGODB_DB, host=MONGODB_HOST, port=MONGODB_PORT)
        data = self.parser.parse_args()
        image = data['image_file']
        audio = data['audio_file']
        fig = Figure(
            data['thing'],
            image.filename,
            get_file_size(image),
            audio.filename,
            get_file_size(audio)
        )
        image.save(image.filename)
        audio.save(audio.filename)
        fig.save()
        db.close()

When I try to send the data I get an 'Internal Server Error' 500 from my requesting client. The flask-rest server will throw---

File "/home/joe/Projects/PyKapi-venv/kapi/resources/figure_resource.py", line 53, in post image.filename, AttributeError: 'NoneType' object has no attribute 'filename' 127.0.0.1 - - [20/May/2018 17:12:25] "POST /figures HTTP/1.1" 500 -

I thought the issue was in my Http request, but not so sure now. I was initially sending my request with Postman, but have recently switched to using curl. This is my curl command---

curl -F thing=Fruits -F image_file=@/home/joe/Projects/Pics/Fruits.jpg -F audio_file=@/home/joe/Projects/Audio/Fruits http://127.0.0.1:5000/figures

Solution

  • [UPDATE] I was using the locations argument in the requestparser() wrong. The location arguement wants the content-type of the request. So I changed it as follows~

    class FiguresResource(Resource):
        parser = reqparse.RequestParser()
        parser.add_argument(
            'thing',
            type=str,
            location='form')
        parser.add_argument(
            'image_file',
            type=FileStorage,
            location='files')
        parser.add_argument(
            'audio_file',
            type=FileStorage,
            location='files')
    
        def post(self):
            data = self.parser.parse_args()
            image = data['image_file']
            audio = data['audio_file']
            image_path = join(IMAGE_FOLDER, image.filename)
            audio_path = join(AUDIO_FOLDER, audio.filename)
    
            db = connect(MONGODB_DB, host=MONGODB_HOST, port=MONGODB_PORT)
            if Figure.objects(visual_aid_path=image_path):
                db.close()
                return {"message": "Visual Aid file with that name already exists"}
            if Figure.objects(audio_aid_path=audio_path):
                db.close()
                return {"message": "Audio file with that name already exists"}
            fig = Figure(
                data['thing'],
                image_path,
                audio_path
            )
            image.save(image_path)
            audio.save(audio_path)
            image.close()
            audio.close()
            fig.save()
            db.close()
    

    `