Many to One association in Flask / SQLAlchemy

Issue

I have two classes one is Dossier and the other is File
I have an association Many to One (Many files can belong to one dossier)
I have a problem when I try to upload a file I need to have the id of the dossier but I just couldn’t get it right
okay let me explain more this is my code:
These are my classes:

from io import BytesIO
from xml.dom.minidom import Identified
from flask import Flask, abort, render_template, request, send_file
from flask_sqlalchemy import SQLAlchemy 
import os
from flask_restful import Api, Resource, reqparse 
from flask_cors import CORS, cross_origin
 
app = Flask(__name__)
CORS(app)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///db.sqlite3'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False 
db = SQLAlchemy(app)
api = Api(app)

class Fichier(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    filename = db.Column(db.String(50))
    data = db.Column(db.LargeBinary)
    type=db.Column(db.String(50))
    size=db.Column(db.Integer)
    idDossier = db.Column(db.Integer, db.ForeignKey('dossier.idD'))
    def __init__(self, filename, data, type, size, idDossier):
        self.filename = filename
        self.data = data
        self.type = type
        self.size = size
        self.idDossier = idDossier
class Dossier(db.Model):
    idD=db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(50))
    idChild= db.Column(db.Integer)
    idFichier = db.relationship('Fichier',  backref='dossier')
    def __init__(self, idD , name , idChild ): 
        self.idD = idD
        self.name = name
        self.idChild = idChild
    
    def json(self): 
        return {"id":self.id , "filename":self.filename , "type":self.type , "size":self.size}

    def toJson(self):
        return {"name":self.name , "idD":self.idD , "idChild":self.idChild}

This is my upload function :

    @app.route('/upload/<id>', methods=['POST'])
     def index(id):
        file = request.files['file']
        file.data = request.files['file'].read()
        file.size=len(file.data)
        type = os.path.splitext(file.filename)
        file.type = type[1]
        file.size=len(file.data)
        file.idDossier = Dossier.query.filter_by(idD=id).first()
        """file.idDossier= Dossier.query.get(Dossier.idD)"""
        upload = Fichier(filename=file.filename, data=file.data , 
        type=file.type , size=file.size , idDossier=file.idDossier)
        db.session.add(upload) 
        db.session.commit()
        return f'Uploaded: {file.filename}'

when I run my code , I get this error in console :
enter image description here

I’m lost if anyone knows how to fix this that would be great. Thank you!

Solution

You need to pass the id of the idDossier, but that’s confusing.

upload = Fichier(
    filename=file.filename,
    data=file.data,
    type=file.type,
    size=file.size,
    idDossier=file.idDossier.idD,
)

According to sqlalchemy documentation, this is the pattern you should be following. Keep it simple, clear and formatted, you will read it easier for sure.

class Fichier(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    ...
    dossier_id = db.Column(db.Integer, db.ForeignKey("dossier.id"))


class Dossier(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    ...
    fichier = db.relationship("Fichier", backref="dossier")

Side note: maybe try to avoid backref for a more explicit code ?

Answered By – BcK

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published