MVC模式下SQLAlchemy关联查询的代码放置位置咨询
问题描述
在MVC架构下开发时,Model文件夹中有两个独立文件的UserModel和PostModel,SQLAlchemy查询逻辑写在模型类中由控制器调用。现在需要通过uid关联查询post和user表,但在PostModel中实现关联查询需要导入UserModel,破坏模型独立性。考虑过创建单独的queries.py存放查询逻辑,但不确定是否为最佳实践及存放位置,寻求其他解决方案。
UserModel 代码
class UserModel(db.Model): __tablename__ = 'user' id = db.Column(db.String(36), primary_key = True) username = db.Column(db.String(50), unique = True) password = db.Column(db.String(100)) def __init__(self, id: str = None, username: str = None, password: str = None) -> None: self.id = id self.username = username self.password = password def serialize(self) -> Dict[str, str]: return { 'id': self.id, 'username': self.username, 'password': self.password } @classmethod def get_users(cls): return cls.query.all() @classmethod def get_user(cls, id): return cls.query.filter_by(id = id).one()
PostModel 代码
class PostModel(db.Model): __tablename__ = 'post' id = db.Column(db.String(36), primary_key=True) uid = db.Column(db.String(36), db.ForeignKey('user.id'), nullable=False) title = db.Column(db.String()) body = db.Column(db.String()) def __init__(self, id: str = None, uid: str = None, title: str = None, body: str = None) -> None: self.id = id self.uid = uid self.title = title self.body = body def serialize(self) -> Dict[str, str]: return { 'id': self.id, 'uid': self.uid, 'title': self.title, 'body': self.body } @classmethod def get_posts(cls): return cls.query.all() @classmethod def get_post_by_id(cls, id: str): return cls.query.filter_by(id = id).one() @classmethod def get_post_by_uid(cls, uid: str): return cls.query.filter_by(uid = uid).all()
解决方案
1. 利用SQLAlchemy的关系定义(推荐)
在模型中定义双向关系,既符合ORM设计思路,又能避免手动导入关联模型的耦合问题:
- 在
UserModel中添加与PostModel的关系:
这里使用字符串posts = db.relationship('PostModel', backref='user', lazy='dynamic')'PostModel'而非直接导入类,SQLAlchemy会自动解析,避免循环导入。 - 在
PostModel中无需额外导入,直接通过post.user就能访问关联的用户对象;反之,user.posts可获取该用户的所有帖子。 - 关联查询示例:
# 获取所有带用户信息的帖子 posts_with_user = PostModel.query.options(db.joinedload(PostModel.user)).all() # 获取某个用户的所有帖子 user = UserModel.get_user(user_id) user_posts = user.posts.all()
这种方式保持了模型的独立性,同时利用ORM的特性简化关联操作。
2. 独立查询模块(你考虑的方案)
创建单独的查询模块是合理的实践,具体建议:
- 可以在
models文件夹下创建queries.py,或者在项目根目录下创建repositories文件夹(更符合DDD思想),存放所有复杂查询逻辑。 - 示例
queries.py内容:from models.user import UserModel from models.post import PostModel from app import db def get_posts_with_users(): return db.session.query(PostModel, UserModel)\ .join(UserModel, UserModel.id == PostModel.uid)\ .all() def get_user_posts_with_user_info(user_id): return db.session.query(PostModel, UserModel)\ .filter(UserModel.id == user_id)\ .join(UserModel)\ .all() - 控制器直接调用这些查询函数即可,模型类只保留基础的单表查询和数据操作方法,职责更清晰。
3. 在控制器中实现关联查询
将关联查询逻辑直接放在控制器中,适合简单的关联场景:
- 示例控制器代码:
from models.user import UserModel from models.post import PostModel def get_posts_with_users(): posts = PostModel.query.join(UserModel, UserModel.id == PostModel.uid).all() # 处理序列化等逻辑 return [{"post": post.serialize(), "user": user.serialize()} for post, user in posts]
这种方式无需修改模型,也不用额外模块,但如果查询逻辑复杂,会导致控制器代码臃肿,适合简单场景。
内容的提问来源于stack exchange,提问作者WhiteHeadbanger
相关产品推荐
相关产品推荐

