我一直在尝试构建一个 Flask/SQLalchemy 网站,该网站允许用户发布旅行经历 - 按旅行进行分组,并能够在每次旅行下发布各种图片和视频。我希望能够根据某些条件查询用户或行程,并显示给定用户或给定行程下发布的图片和视频的数量。希望建立一个查询,提供图片数量和视频数量以及行程或用户对象。
这是我的模型:
from flask import Flask, render_template, url_for, request, redirect,send_file
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.sql import select
from sqlalchemy.sql.expression import func, or_
from datetime import datetime
import time
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test_v1.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
app.app_context().push()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), unique = False, nullable=False)
trips = db.relationship('Trips', backref='user', lazy=True)
def __repr__(self):
return f"User('{self.id}','{self.name}')"
class Trips(db.Model):
id = db.Column(db.Integer, primary_key=True)
location = db.Column(db.String(20), unique = False, nullable=False)
departure_date = db.Column(db.DateTime, nullable=False)
return_date = db.Column(db.DateTime, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
pics = db.relationship('Pictures', backref='trips', lazy=True)
vids = db.relationship('Videos', backref='trips', lazy=True)
def __repr__(self):
return f"Trips('{self.id}','{self.location}')"
class Pictures(db.Model):
id = db.Column(db.Integer, primary_key=True)
file_name = db.Column(db.String(40), unique = False, nullable=False)
date_taken = db.Column(db.DateTime, nullable=False)
trip_id = db.Column(db.Integer, db.ForeignKey('trips.id'), nullable=False)
def __repr__(self):
return f"Pictures('{self.id}','{self.file_name}')"
class Videos(db.Model):
id = db.Column(db.Integer, primary_key=True)
file_name = db.Column(db.String(40), unique = False, nullable=False)
date_taken = db.Column(db.DateTime, nullable=False)
length = db.Column(db.Float, nullable=False)
trip_id = db.Column(db.Integer, db.ForeignKey('trips.id'), nullable=False)
def __repr__(self):
return f"Videos('{self.id}','{self.file_name}','{self.length}')"
db.create_all()
我已经弄清楚如何查询行程并获取一列图片计数,如下所示:
pic_count=db.session.query(Trips,func.count(Pictures.id)).join(Pictures,Trips.id==Pictures.trip_id).group_by(Pictures.trip_id)
但是,如果我尝试通过加入视频表来扩展此功能,则总计数似乎会搞砸 - 就像将图片数量乘以视频数量一样。
还可以这样查询吗?
当您必须跨不同组进行计数时,我会使用子查询。
with Session(conn) as session:
# Count up pictures per trip.
picture_subq = select(
Picture.trip_id,
func.count(Picture.id).label('picture_count')
).group_by(Picture.trip_id).subquery()
# Count up videos per trip.
video_subq = select(
Video.trip_id,
func.count(Video.id).label('video_count')
).group_by(Video.trip_id).subquery()
# Now get trips with those counts.
# - We use outerjoin because some trips have no matching
# picture and/or video count and we want those trips
# to still be included.
# - When those trips are included that missing count would
# normally be NULL/None but we use coalesce() to tell
# the database to convert that value to 0.
# - When referencing columns on the subqueries we need to
# use `.c.` to access the columns.
q = select(
Trip,
func.coalesce(picture_subq.c.picture_count, 0),
func.coalesce(video_subq.c.video_count, 0)
).outerjoin(
picture_subq, Trip.id == picture_subq.c.trip_id
).outerjoin(
video_subq, Trip.id == video_subq.c.trip_id)
for trip, picture_count, video_count in session.execute(q).all():
print (trip.id, picture_count, video_count)