【问题标题】:(flask)-sqlalchemy query, have to import all models(flask)-sqlalchemy 查询,必须导入所有模型
【发布时间】:2015-05-26 20:18:15
【问题描述】:

我在使用 Flask 和 Flask-SQLAlchemy 时遇到问题,对于任何查询,我都需要导入所有相关模型。

现在我的 auth.views.py 看起来像这样(前几行编程这个东西所以只是一个测试视图)

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}) 

现在我收到一个错误

"InvalidRequestError: 当初始化映射器 Mapper|User|user 时,表达式'Course' 找不到名称("name 'Course' 未定义")。如果这是一个类名,请考虑将此关系()添加到定义了两个依赖类之后的类。”

我有一个项目,我有一个这样的模型包

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

我的用户类有一个多对多的课程和一对多的提交。

这是通过导入课程来解决的(然后是提交,然后是那里的关系,最终基本上是所有模型。)

在 Pyramid 项目中,我们也使用 SQLAlchemy,但我不必导入所有模型来完成我的工作。有什么想法吗?我真的想不通,我也无法谷歌它。

用户看起来像这样

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    

【问题讨论】:

  • 如果您从不导入您的models.course 模块,则代码永远不会执行,您的课程类也永远不会真正创建并注册到sys.modules
  • 我希望不必事先导入所有模块。每次你引入新东西时,手动做这件事会很糟糕。我还假设我们连接到数据库的元数据将加载所有表。但感谢您的指点。我会在答案中给出我自己的解决方案,
  • 我的建议是将您的模型导入一个模块,而不是像那样拆分它们。 "Flat is better than nested."
  • 当模型很小时这很好,但是当它们变大并接收更多方法时,将它们分开会更具可读性。至少这是我个人对此的感觉,可能是错误的感觉:))

标签: python flask sqlalchemy


【解决方案1】:

好吧,显然你无法绕过加载所有模块。我不想手动执行此操作,因此我在__init__.py 中使用了此功能。现在所有模块都将像评论所说的那样执行。

import inspect                                                              
import pkgutil                                                                 
import importlib                                                               
import sys                                                                     


def import_models():                                                           
    thismodule = sys.modules[__name__]                                         

    for loader, module_name, is_pkg in pkgutil.iter_modules(                   
            thismodule.__path__, thismodule.__name__ + '.'):                   
        module = importlib.import_module(module_name, loader.path)             
        for name, _object in inspect.getmembers(module, inspect.isclass):      
            globals()[name] = _object                                                                                     

import_models()        

【讨论】:

    【解决方案2】:

    如果你真的想坚持每类一个文件的方案,在我看来,更简洁的选择是在模型包的 init 中进行导入:

    models/__init__.py:

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

    然后你可以将类导入为

    from models import User
    

    这使得事情更具可读性,并允许将每个类一个文件方案与包含多个类的模块混合在一起,同时仍然能够以“平面”方式从 models 导入所有类。

    【讨论】:

    • 我有一个动态执行的解决方案,但您对可读性的看法是绝对正确的。所以我最终选择了你的解决方案。
    • 这对我有用。如果您仍然遇到任何问题,请仔细查看错误消息,它会显示缺少的内容。可能是某些文件超出模块(例如,您为多对多关系创建的普通表),如果是这样,请在 init.py 中导入这些文件
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-18
    • 2013-07-24
    相关资源
    最近更新 更多