Home > Software design >  How to split a file into filename and data and insert it to a database in flask?
How to split a file into filename and data and insert it to a database in flask?

Time:07-14

I am making a homework system on my site which should include the fact that the teacher will be able to create a task with an attachment, but I don't know how to break up the file that the teacher sends to the file name and file data in the table in the mysql database. I am programming it in vanilla flask, could someone please advise me how to do it, I would be grateful. So far I have this code which reports this error:

AttributeError AttributeError: 'str' object has no attribute 'filename'

Sample code where I create a homework with an attachment, but it is not working:

@app.route("/create_homework", methods=["POST", "GET"])
@isLoggedIn
def create_homework():
    if session["group_id"] != Group.REDITEL and session["group_id"] != Group.UCITEL:
        abort(401, description="Nemáš dostatečné oprávnění")
    
    form = HomeworkForm()
    if request.method == "POST":
        connection = mysql.connection
        cursor = connection.cursor(prepared=True)

        hmTitle = request.form.get("hmTitle")
        description = request.form.get("description")
        date_of_completion = request.form.get("date_of_completion")
        classname = session["class"]
        school = session["school"]

        if session["class"] == None:
            return "Učitel není přiřazen k žádné třídě"

        if(request.method == "POST"):
            usersName  = loadUserNameFromClass(classname, school)
            for userName in usersName:
                if form.validate_on_submit():
                    attachment_data = form.attachment.data
                    attachment_name = secure_filename(attachment_data.filename)

                    file_stream = Binary(attachment_data.read(1024))
                    attachment_data.save(file_stream)

                    cursor.execute("INSERT INTO homeworks (id, userName, homework_title, homework_description, school, class, date_of_completion, status, attachment_name, attachment_data) VALUES (0, %s, %s, %s, %s, %s, %s, 0, %s, %s);", (userName, hmTitle, description, school,classname, date_of_completion, attachment_name, file_stream, ))
                clearForm(form)
                connection.commit()
                return redirect(url_for("homeworks"))
            else:
                return redirect(url_for("homeworks"))
            cursor.close()
            connection.close()
            
    return render_template("profile/homework/create_homework.html", form=form)

Sample code where I select the attachment so that the user can download it:

@app.route("/download_file/<int:id>")
@isLoggedIn
def download_file(id):
    connection = mysql.connection
    cursor = connection.cursor(prepared=True)

    file_name = get_file_name(cursor, id)
    file_data = get_file_data(cursor, id)

    return send_file(BytesIO(file_data), attachment_filename=file_name, as_attachment=True)

def get_file_name(cursor, id):
    cursor.execute("SELECT attachment_name FROM homeworks WHERE id=%s;", (id, ))
    output = cursor.fetchone()

    return output[0]

def get_file_data(cursor, id):
    cursor.execute("SELECT attachment_data FROM homeworks WHERE id=%s;", (id, ))
    output = cursor.fetchone()

    return output[0]

HomeworkForm code:

class HomeworkForm(FlaskForm):
    hmTitle = TextField('Titulek', [validators.DataRequired(), validators.Length(min=1, max=200)])
    description = TextAreaField("Popis", [validators.DataRequired()])
    attachment = FileField('Příloha', validators=[FileRequired(), FileAllowed(['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'zip', 'rar'], 'Povolené typy souborů: pdf, doc, docx, xls, xlsx, ppt, pptx, zip, rar')], id='attachment')   
    date_of_completion = DateTimeLocalField('Datum odevzdání', format='%m/%d/%y', validators=[validators.DataRequired()])
    submit = SubmitField("Vytvořit")

HTML code:

<form method="POST" action="/create_homework"  enctype="multipart/form-data">
        {{ form.csrf_token }}

        <strong>{{ form.hmTitle.label() }} </strong>
        {{ form.hmTitle(id="hmTitle", ) }}

        <br>
        <strong>{{ form.description.label() }} </strong>
        {{ form.description(id="description", ) }}
        <br>
        <strong>{{ form.attachment.label() }} </strong>
        {{ form.attachment(id="attachment", ) }}
        <br>
        <strong>{{ form.date_of_completion.label() }} </strong>
        {{ form.date_of_completion(id="date_of_completion", ) }}

        <br>
        {{ form.submit(id="submit", ) }}

        <!--<input type="file" name="attachment">-->
        <br>
        {%if success == False%}
            <p style="color: red;">Zpráva nebyla zaslána</p>
        {%endif%}
        <hr>
        <button  href="/homeworks" id="return-back">Vrátit zpátky</button>
    </form>

CodePudding user response:

You haven't provided the definition of your HomeworkForm() so it's hard to provide an answer but I can tell you why you're seeing that exception.

On the line if attachment(attachment.filename): the attachment variable is a string and doesn't have the property 'filename' on it.

You need to change the line attachment = request.form.get("attachment"). If you are using WTForms FileField, this returns the path to a file, which is why you're getting a string here and seeing that exception.

Here's a tutorial that goes into detail on how to use flask and WTForms to upload a file.

Edit: Looking at the documentation for Flask-WTForms's FileField

To get the data of the file:

if form.validate_on_submit():
    homework_data = form.attachment.data
    homework_filename = secure_filename(homework_data.filename)

The docs also mention making sure you set the encoding type for the form in your html:

<form method="POST" enctype="multipart/form-data">
        
     
  • Related