SQLAlchemy - 在结果中使用多个 func.count() 进行查询

问题描述 投票:0回答:1

我一直在尝试构建一个 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)

但是,如果我尝试通过加入视频表来扩展此功能,则总计数似乎会搞砸 - 就像将图片数量乘以视频数量一样。

还可以这样查询吗?

sqlalchemy flask-sqlalchemy
1个回答
0
投票

当您必须跨不同组进行计数时,我会使用子查询。

    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)
© www.soinside.com 2019 - 2024. All rights reserved.