python - 在烧瓶 sqlalchemy sqlite 关系定义和后续查询方面需要帮助?
问题描述
我已阅读并查看了所有 sqlalchemy 和 flasksqlalchemy 文档,并且我尝试了以下代码的几种不同迭代,但我无法使用 flask-sqlalchemy 方法实现我想要的。
我定义了 3 个表:Users、Downloads 和 ProjectProfiles。
我正在尝试根据“当前用户”提取所有下载和项目配置文件信息。
我可以使用以下标准 SQL 查询来实现这一点:
SELECT u.first_name, u.last_name, pp.project_name, pp.project_number, cd.file_name, cd.original_date
FROM users u
INNER join customer_data cd
ON u.client_id = cd.client_id
INNER join project_profile pp
ON cd.project_id = pp.project_id
WHERE u.id = 3
AND cd.original_date > '2019-11-24'
我的 flask-sqlalchemy 模型定义如下:
class Users(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
client_id = db.Column(db.String(10), index=True)
first_name = db.Column(db.String(64))
last_name = db.Column(db.String(64))
email = db.Column(db.String(120), index=True, unique=True)
downloads = db.relationship('Downloads', backref='file_owner', lazy='dynamic')
class Downloads(db.Model):
__tablename__ = 'client_downloads'
id = db.Column(db.Integer, primary_key=True)
client_id = db.Column(db.String(10), db.ForeignKey('users.client_id'), index=True)
project_id = db.Column(db.String(10), index=True)
file_type = db.Column(db.String(255))
file_name = db.Column(db.String(255))
file_extension = db.Column(db.String(5))
file_directory = db.Column(db.TEXT())
original_date = db.Column(db.DateTime)
project_info = db.relationship('ProjectProfiles', foreign_keys='ProjectProfiles.project_id', backref='pinfo', lazy='dynamic')
class ProjectProfiles(db.Model):
__tablename__ = 'project_profile'
id = db.Column(db.Integer, primary_key=True)
project_id = db.Column(db.String(10), db.ForeignKey('client_downloads.project_id'), index=True)
project_name = db.Column(db.String(40))
project_number = db.Column(db.String(30))
client_id = db.Column(db.String(10))
created_date = db.Column(db.DateTime)
modified_date = db.Column(db.DateTime)
当使用以下命令使用flask shell进行测试时,我可以获得特定用户的下载,但是如果我尝试获取与用户/下载关联的项目配置文件,我似乎无法访问该信息:
获取下载的 Flask shell 命令:
[2019-12-02 13:49:04,444] INFO in __init__: Example startup
Python 3.6.8 (default, Aug 7 2019, 17:28:10)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
App: app [testing]
Instance: /var/www/testing/instance
>>> from app import db
>>> from app.models import Users, Downloads, ProjectProfiles
>>> from datetime import datetime, timedelta
>>> u = Users.query.get(2)
>>> curr_date = datetime.utcnow()
>>> diff_date = curr_date - timedelta(weeks=2)
>>> dloads = u.downloads.filter(Downloads.original_date > diff_date).all()
dloads 的结果:
>>> dloads
[<Downloads 240169>]
>>> for d in dloads:
... print("project_id:", d.project_id)
...
project_id: 20635
从 dloads 访问 project_info 定义/关系时的结果:
>>> for d in dloads:
... print(d.project_info)
...
SELECT project_profile.id AS project_profile_id, project_profile.project_id AS
project_profile_project_id, project_profile.projname AS project_profile_projname,
project_profile.projnumber AS project_profile_projnumber, project_profile.client_id AS
project_profile_client_id, project_profile.created_date AS project_profile_created_date,
project_profile.modified_date AS project_profile_modified_date
FROM project_profile
WHERE ? = project_profile.project_id
尝试将 projs 变量设置为 dloads.project_info 时出错:
>>> projs = dloads.project_info.query.all()
Traceback (most recent call last): File "<console>", line 1, in <module>
AttributeError: 'list' object has no attribute 'project_info'
>>>
如果我首先从下载返回单个值并专门过滤/加入 project_ids,则成功结果:
>>> d = Downloads.query.get(2)
>>> d
<Downloads 2>
>>> projs = d.project_info.filter(ProjectProfiles.project_id == d.project_id).all()
>>> projs
[<ProjectProfiles 3779>]
>>> for p in projs:
... print("project_name:", p.project_name)
...
project_name: Test Project Profile
当前用于下载的烧瓶路线定义:
@app.route('/testing', methods=['GET', 'POST'])
@app.route('/testing/index', methods=['GET', 'POST'])
@login_required
def index():
curr_date = datetime.utcnow()
diff_date = curr_date - timedelta(weeks=52)
downloads = current_user.downloads.filter(Downloads.original_date > diff_date).all()
return render_template('index.html', downloads=downloads, user=current_user)
即使在上面的路由定义中,从技术上讲,我只返回特定于下载的字段,而不是像我习惯使用上面显示的 SQL 查询那样返回下载和用户数据的组合。
我想做的是定义一个对象/变量,它将下载和项目信息一起返回到由当前用户过滤的单个对象/变量中,如上所示!
任何帮助深表感谢!
编辑 - 根据接受的答案,我想出了以下对我有用的方法
downloads = db.session.query(Downloads).join(Users, ProjectProfiles).filter(Downloads.original_date > diff_date, Users.id == current_user.id)
解决方案
关于错误,我们必须考虑到 dload 是一个列表而不是单个下载。此外,project_info 也是一个列表。因此,根据您的逻辑,您需要获取列表中的第一个元素:
projs = dloads[0].project_info[0].query.all()
如果要在一个结果中从不同表中获取结果,则结果是从不同表中选择的属性列表(不再是单个 sqlalchemy 对象)。至少如果你想有一个单一的声明。例如:
combinedresult = db.session.query(ProjectProfiles.id, Downloads.id,
Users.id).filter(Downloads.original_date > diff_date, Users.id==1).all()
为项目配置文件、下载、受日期约束限制的用户和特定用户选择 ID。
推荐阅读
- ios - 无法设置 cocoapods。Cocoapods 设置问题
- node.js - 节点不会更新角度
- c# - 如何将对象的实例化转换为 lambda 表达式
- r - 如何在 data.table 的日期类中应用唯一性
- c# - 如何使用反射将 DI 的所有接口实现配置为 IOptions<>?
- python - Pandas 在多个列上合并忽略 NaN
- python - 在 Django 字段上执行加法和乘法的最佳方法
- typescript - Typescript中未定义数组作为类成员
- windows - Google Cloud SDK 无法安装 '.exe;.bat;.com' 不是可识别的命令
- scala - 展平非元素值的数据框