Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 查询由其他表进一步链接的一对多关系_Python_Sqlalchemy_Pyramid - Fatal编程技术网

Python 查询由其他表进一步链接的一对多关系

Python 查询由其他表进一步链接的一对多关系,python,sqlalchemy,pyramid,Python,Sqlalchemy,Pyramid,对不起,我想不出更好的通用标题了。我正在使用金字塔和sqlalchemy构建一个照片投票应用程序。完整的模式和orm在最后,但最相关的信息是 照片表格 投票带有照片id和用户id的表格,其中用户id标识了对照片投赞成票或反对票的用户 类别带有照片类别列表的表格 phototegory表格链接photo和category表格 在应用程序的主照片提要中,我希望按照以下顺序显示照片 用户未投票的照片先于他/她投票的照片 在上面的每组中(未投票,然后投票),按照片的现有投票数降序排序 该应用程序还可以灵

对不起,我想不出更好的通用标题了。我正在使用金字塔和sqlalchemy构建一个照片投票应用程序。完整的模式和orm在最后,但最相关的信息是

  • 照片
    表格
  • 投票
    带有
    照片id
    用户id
    的表格,其中用户id标识了对照片投赞成票或反对票的用户
  • 类别
    带有照片类别列表的表格
  • phototegory
    表格链接
    photo
    category
    表格
  • 在应用程序的主照片提要中,我希望按照以下顺序显示照片

  • 用户未投票的照片先于他/她投票的照片
  • 在上面的每组中(未投票,然后投票),按照片的现有投票数降序排序
  • 该应用程序还可以灵活地只显示特定类别的照片

    我现在实施的方式是

    • 仅获取所需类别的照片
    i、 e

    • 按投票数对照片进行排序
    i、 e

    • 反复浏览
      照片
      ,查看用户是否已投票,并将照片附加到
      已投票
      未投票
      列表/数组中
    然而,这是如此低效,因为我必须搜索所有的照片,用户以前投票给每一张照片在
    照片
    ,所以我想知道什么是正确和有效的方式来做这件事。。。谢谢

    模式

      photo_table = schema.Table('photo', metadata,
      schema.Column('id', types.Integer,
        schema.Sequence('photo_seq_id'), primary_key=True),
      schema.Column('caption', types.UnicodeText(), nullable=True),
      schema.Column('timestamp', types.TIMESTAMP(), default=datetime.now()),
      schema.Column('last_updated', types.TIMESTAMP(), default=datetime.now(),),
      schema.Column('spam', types.Boolean, default=0),
      schema.Column('trash', types.Boolean, default=0),
      schema.Column('image_path', types.Unicode(255), nullable=False),
      schema.Column('user_id', types.Integer, schema.ForeignKey('user.id', ondelete='CASCADE')),
      mysql_engine='InnoDB'
    )
    
    category_table = schema.Table('category', metadata,
      schema.Column('id', types.Integer,
        schema.Sequence('category_seq_id'), primary_key=True),
      schema.Column('name', types.Unicode(255), nullable=False, unique=True),
      mysql_engine='InnoDB'
    )
    
    photocategory_table = schema.Table('photocategory', metadata,
      schema.Column('photo_id', types.Integer, schema.ForeignKey('photo.id', ondelete='CASCADE'), primary_key=True),
      schema.Column('category_id', types.Integer, schema.ForeignKey('category.id', ondelete='CASCADE'), primary_key=True),
      mysql_engine='InnoDB'
    )
    
    vote_table = schema.Table('vote', metadata,
      schema.Column('id', types.Integer,
        schema.Sequence('vote_seq_id'), primary_key=True),
      schema.Column('timestamp', types.TIMESTAMP(), default=datetime.now()),
      schema.Column('upvote', types.Boolean, nullable=False),
      schema.Column('photo_id', types.Integer, schema.ForeignKey('photo.id', ondelete='CASCADE')),
      schema.Column('user_id', types.Integer, schema.ForeignKey('user.id', ondelete='CASCADE')),
      mysql_engine='InnoDB'
    )
    
    ORM映射器

    orm.mapper(Photo, photo_table, properties={
      'votes': orm.relation(Vote, backref='photo', lazy='dynamic'),
      'categories': orm.relation(Category, secondary=photocategory_table, backref='photos'),
    })
    
    orm.mapper(User, user_table, properties={
      'photos': orm.relation(Photo, backref='owner'),
      'votes': orm.relation(Vote, backref='voter', lazy='dynamic'),
    })
    

    也许使用SQL本身做这件事是一个更好的主意。以下内容未经测试,可能无法使用,但您可以调整它以满足您的需要

    您可以通过以下方式选择某个类别的照片:

    cat_photos = session.query(PhotoCategory.photo_id.label('pid')).options(lazyload('*')).filter(PhotoCategory.category_id==SOMEID).subquery()
    
    加入用户和照片表以获得用户可以投票的照片列表。假设用户不能对自己的照片进行投票,您将获得

    elig_photos = session.query(User).join(Photos,Photos.user_id!=User.id).options(lazyload('*')).with_entities(Photos.id.label('pid'),User.id.label('uid').subquery()
    
    现在,您可以将其加入投票表和子查询,以获取用户尚未投票的特定类别的照片

    not_voted = session.query(elig_photos).outerjoin(Votes,and_(Votes.photo_id==elig_photos.c.pid,Votes.user_id==elig_photos.c.uid)).join(cat_photos,cat_photos.c.pid==elig_photos.c.pid).with_entities(elig_photos.c.pid.label('photo_id'),Votes.upvote.label('upvote')).options(lazyload('*')).filter(User.id==SOMEUSER).filter(Votes.upvote==None).all()
    
    获取按投票数排序的此类照片。我们将不得不做一个左加入,因为可能有一些照片还没有人投票

    sorted_votes = session.query(cat_photos).outerjoin(Votes,cat_photos.c.pid==Votes.photo_id).with_entities(cat_photos.c.pid.label('pid'),func.coalesce(func.sum(Votes.upvote),0).label('sum_votes')).options(lazyload('*')).group_by(cat_photos.pid).order_by(desc('sum_votes')).all()
    
    注意-我在每个查询中添加了一个选项
    options(lazyload('*'))
    ,以使关系延迟加载

    现在您有两个列表-

    • sorted_vows
      以降序方式列出该类别的照片 投票顺序(未被任何人投票的照片0票)
    • 未投票
      其中列出了未经用户投票的此类照片
    请注意,用户上传的此类照片将是第一个列表的一部分

    您可以在python中处理这两个列表,首先根据它们在第一个列表中的索引显示not_voted,然后按原样显示第一个列表的其余部分

    not_voted_sorted = sorted(not_voted,key=lambda x:sorted_votes.index(x))
    rest_of_the_photos = [y for y in sorted_votes if y not in not_voted]
    
    如果您只从这些查询中获取照片ID,这将是一个好主意(IMO)。整个Photo对象列表可以从DB中单独获取,并保存在以Photo_id为键的字典中。因此,如果您知道要显示的照片id,则可以在模板中显示整个照片详细信息

    最后一点注意:如果某项操作不起作用,请尝试为您尝试执行的操作编写一个简单的SQL,然后编写与SQLAlchemy等效的语句并打印该语句,以比较手工编写的SQL和SQLAlchemy生成的SQL是否相同

    sorted_votes = session.query(cat_photos).outerjoin(Votes,cat_photos.c.pid==Votes.photo_id).with_entities(cat_photos.c.pid.label('pid'),func.coalesce(func.sum(Votes.upvote),0).label('sum_votes')).options(lazyload('*')).group_by(cat_photos.pid).order_by(desc('sum_votes')).all()
    
    not_voted_sorted = sorted(not_voted,key=lambda x:sorted_votes.index(x))
    rest_of_the_photos = [y for y in sorted_votes if y not in not_voted]