greyli / bluelog

Check out the newer version (2024) of this project: https://github.com/greyli/greybook
MIT License
454 stars 662 forks source link

邻接列表关系疑问求解 #17

Closed archcst closed 1 year ago

archcst commented 5 years ago

对「邻接列表关系」理解上还有一些问题,希望老师解惑

models.py 中这三行代码我的理解如下:

    # comment.replied_id 为一个指向评论(父级,也是自身)的外键
    replied_id = db.Column(db.Integer, db.ForeignKey('comment.id'))

    # comment.replies 为同一评论下的所有“回复”(子级,因为「多」所以变量名采用了复数形式)
    replies = db.relationship('Comment', back_populates='replied', cascade='all, delete-orphan')

    # comment.replied 为被回复的评论(父级,也是「一」这一侧的关系定义)
    replied = db.relationship('Comment', back_populates='replies', remote_side=[id])

之所以有第三行(replied)是「一」这一侧必须要有关系定义,从而SQLAlchemy才能到对应的「多」侧去找外键字段(replied_id)。

comment.replied_id 对回复调用才有返回值,返回该回复对应的评论的 id。(返回父级 id) comment.replies 对评论调用才有返回值,返回该评论对应的回复对象构成的列表。(返回子级对象集合) comment.replied 对回复调用才有返回值,返回该回复对应的评论对象。(返回父级对象)

那么问题来了,fakes.py 中:

    for i in range(salt):
        comment = Comment(
            ...
            # 第一句
            replied=Comment.query.get(random.randint(1, Comment.query.count())),
            # 第二句
            post=Post.query.get(random.randint(1, Post.query.count()))
        )

第一句理解为把 Comment(子级/回复) 对象的 replied 属性设置为某个随机的 Comment(父级/评论) 对象。

第二句为什么需要再为这个「回复」设置关联的「文章Post」呢? 「回复」跳过「评论」直接对应到「文章」的目的是什么,会不会出现逻辑错误?

greyli commented 1 year ago

第二句这部分的代码是错的,并不需要设定 post。新版本修复了这个问题:

def fake_replies(count=50):
    for _ in range(count):
        comment_count = db.session.execute(select(func.count(Comment.id))).scalars().one()
        replied = db.session.get(Comment, random.randint(1, comment_count))
        comment = Comment(
            author=fake.name(),
            email=fake.email(),
            site=fake.url(),
            body=fake.sentence(),
            created_at=fake.date_time_this_year(before_now=False, after_now=True),
            reviewed=True,
            replied=replied,
            post=replied.post
        )
        db.session.add(comment)
    db.session.commit()

https://github.com/greyli/new-bluelog/blob/main/bluelog/fakes.py#L94-L95

感谢你的详尽分析,陈同学 :P