Search code examples
pythonflasksqlalchemy

(flask)-sqlalchemy query, have to import all models


I have a problem with Flask and Flask-SQLAlchemy where for any query I would need to import all the related models.

Now my auth.views.py looks like this (first few lines of programming this thing so just a test view)

from flask import jsonify                                                   

from . import auth                                                          
from app.models.user import User                                            


@auth.route('/', methods=['GET'])                                            
def index():                                                                 
    users = User.query.all()                                                     
    return jsonify({'name': users[0].name}) 

Now I'm getting an error

"InvalidRequestError: When initializing mapper Mapper|User|user, expression 'Course' failed to locate a name ("name 'Course' is not defined"). If this is a class name, consider adding this relationship() to the class after both dependent classes have been defined."

I have a project where i have a models package like so

app                                                                         
├── auth                                                                    
│   ├── __init__.py                                                         
│   └── views.py                                                            
├── __init__.py                                                             
└── models                                                                  
    ├── assignment.py                                                       
    ├── base.py                                                             
    ├── client.py                                                           
    ├── course.py                                                           
    ├── __init__.py                                                         
    ├── submission.py                                                       
    └── user.py    

my user class has a many to many with Course and a one to many with Submission.

This is solved by importing the Course (and then Submission, and then the relations from there, eventually all the models basically.)

At work for Pyramid projects we also work with SQLAlchemy but I never have to import all the models to do my work. Any ideas whats up? I really can't figure this out and I haven't been able to google it.

User looks like this

user_course = db.Table(                                                     
    'user_course', db.Model.metadata,                                          
    db.Column('student_id', UUID, db.ForeignKey('user.id'),                    
              primary_key=True),                                               
    db.Column('course_id', UUID, db.ForeignKey('course.id'),                   
              primary_key=True)                                                
)                                                                              


class User(db.Model):                                                          
    id = db.Column(UUID, default=lambda: str(uuid.uuid4()), primary_key=True) 
    firstname = db.Column(db.String(100), nullable=False)                      
    lastname = db.Column(db.String(100), nullable=False)                       
    insertion = db.Column(db.String(15))  # tussenvoegsel                      
    # email = db.Column(db.String, nullable=False, unique=True)                
    password_hash = db.Column(db.String, nullable=False)                       

    enrolled_courses = db.relationship('Course', secondary=user_course,        
                                       backref='students')                     
    managed_courses = db.relationship('Course', backref='teacher')             

    submissions = db.relationship('Submission', backref='student')             

    @property                                                                  
    def name(self):                                                            
        return "{}{}{}".format(                                                
            self.firstname + " ",                                              
            self.insertion + " " if self.insertion else "",                    
            self.lastname                                                      
        )                                                                      

    @property                                                                  
    def password(self):                                                        
        raise AttributeError("Password is not a readable attribute")           

    @password.setter                                                           
    def password(self, password):                                              
        self.password_hash = bcrypt.hashpw(password, bcrypt.gensalt(12))       

    def verify_password(self, password):                                       
        return bcrypt.hashpw(password, self.password_hash) == \                
            self.password_hash    

Solution

  • If you really want to stick to the one-file-per-class scheme, in my opionion, the cleaner option would be to do the imports in the model package's init:

    models/__init__.py:

    from user import User
    from client import Client
    from course import Course
    # plus your remaining classes
    

    Then you can import the classes as

    from models import User
    

    which makes things more readable and would allow to mix the one-file-per-class scheme with modules containing multiple classes, while still being able to import all classes in a "flat" manner from models.