greyli / bluelog

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

有关虚拟数据中评论回复(replies)及相关代码的优化建议 #1

Closed AngelLiang closed 6 years ago

AngelLiang commented 6 years ago

首先不得不赞美作者几句,您的书籍和源码简直是棒极了!excellent!在闲暇时间阅读您的书籍,并配以github源码进行“食用”,感觉以前使用Flask编写项目时,一直紊乱的项目组织架构及代码设计思路逐渐理顺,恍然大悟的感觉油然而生,同时对您的钦佩之情也如滔滔江水绵延不绝。

当然,阅读您的源码时,遇到不太对劲的地方我会尝试修改或优化,然后提出来。如果无意让您感到吹毛求疵,还请见谅。

下面是这次的主题:「尽量使虚拟数据接近真实的数据」。当然,Faker生成的sentence和text都是毫无意义的,这个就无所谓了。我留意的是生成评论回复的虚拟数据。

先放上原始代码,位置在bluelog/fakes.py

def fake_comments(count=500):
    # ...
    # replies
    for i in range(salt):
        comment = Comment(
            author=fake.name(),
            email=fake.email(),
            site=fake.url(),
            body=fake.sentence(),
            timestamp=fake.date_time_this_year(),
            reviewed=True,
            replied=Comment.query.get(random.randint(1, Comment.query.count())),
            post=Post.query.get(random.randint(1, Post.query.count()))
        )
        db.session.add(comment)
    db.session.commit()

以上代码功能上没有问题,但是不符合以下逻辑:

  1. 评论回复和评论应该是在同一篇文章内
  2. 评论回复的时间肯定是在该评论的时间之后

因此,对以上代码做了以下优化:

  1. 使用了fake.date_time_between_dates()确保评论回复在评论时间之后;
  2. 评论回复和评论都关联同一篇文章。
def fake_comments(count=500):
    # ...
    # replies
    for i in range(salt):
        comment = Comment.query.get(random.randint(1, Comment.query.count()))
        reply = Comment(
            author=fake.name(),
            email=fake.email(),
            site=fake.url(),
            body=fake.sentence(),
            reviewed=True,

            # 确保回复的时间在评论的时间之后,并且不超过现在的时间
            timestamp=fake.date_time_between_dates(comment.timestamp),
            replied=comment,     # 关联评论
            post=comment.post    # 回复与评论是同一篇文章
        )
        db.session.add(reply)
    db.session.commit()

写到这里本来以为结束了。但转念一想似乎还有点问题:

  1. 评论时间应该是比文章发布时间晚
  2. fake.date_time_this_year()这个生成时间的方法,如果是在1月1日生成会不会有点问题

关于第一点,同上面的修改方式一样了;

关于第二点,经过测试,我把本地时间调到2019年1月1日11点00分,生成的虚拟数据有的超过了该时间点,成了“未来的数据”。而且所有的虚拟数据的timestamp都集中在2019年1月1日,也不是很好。

经过我查阅相关资料,把fake.date_time_this_year()改为fake.past_datetime()就可以了,fake.past_datetime()默认是以一个月前的时间为起点随机生成时间,可以fake.past_datetime('-1y')这样调用,以一年前的时间为起点随机生成时间。

这样,需要修改的代码如下:

# ...

def fake_posts(count=50):
    for i in range(count):
        post = Post(
            title=fake.sentence(),
            body=fake.text(2000),
            category=Category.query.get(random.randint(1, Category.query.count())),
            # timestamp=fake.date_time_this_year()      # modify this
            timestamp=fake.past_datetime('-1y')
        )

        db.session.add(post)
    db.session.commit()

def fake_comments(count=500):
    for i in range(count):
        post = Post.query.get(random.randint(1, Post.query.count()))
        comment = Comment(
            author=fake.name(),
            email=fake.email(),
            site=fake.url(),
            body=fake.sentence(),
            # timestamp=fake.date_time_this_year(),     # modify this
            timestamp=fake.date_time_between_dates(datetime_start=post.timestamp),
            reviewed=True,
            post=post
        )
        db.session.add(comment)

    salt = int(count * 0.1)
    for i in range(salt):
        # unreviewed comments
        post = Post.query.get(random.randint(1, Post.query.count()))
        comment = Comment(
            author=fake.name(),
            email=fake.email(),
            site=fake.url(),
            body=fake.sentence(),
            # timestamp=fake.date_time_this_year(),     # modify this
            timestamp=fake.date_time_between_dates(datetime_start=post.timestamp),
            reviewed=False,
            post=post
        )
        db.session.add(comment)

        # from admin
        post = Post.query.get(random.randint(1, Post.query.count()))
        comment = Comment(
            author='Mima Kirigoe',
            email='mima@example.com',
            site='example.com',
            body=fake.sentence(),
            # timestamp=fake.date_time_this_year(),     # modify this
            timestamp=fake.date_time_between_dates(datetime_start=post.timestamp),
            from_admin=True,
            reviewed=True,
            post=post
        )
        db.session.add(comment)
    db.session.commit()

    # replies
    for i in range(salt):
        comment = Comment.query.get(random.randint(1, Comment.query.count()))
        reply = Comment(
            author=fake.name(),
            email=fake.email(),
            site=fake.url(),
            body=fake.sentence(),
            reviewed=True,
            # timestamp=fake.date_time_this_year(),            
            # replied=Comment.query.get(random.randint(1, Comment.query.count())),
            # post=Post.query.get(random.randint(1, Post.query.count()))

            # 确保回复的时间在评论的时间之后,并且不超过现在的时间
            timestamp=fake.date_time_between_dates(datetime_start=comment.timestamp),
            replied=comment,     # 关联评论
            post=comment.post    # 回复与评论是同一篇文章
        )
        db.session.add(reply)
    db.session.commit()

# ...
greyli commented 6 years ago

谢谢,很高兴你能认可这本书。如果有时间的话,欢迎在亚马逊豆瓣写一个评价,帮助别人进一步了解这本书。

你说的提议很合理,不过我个人认为虚拟数据的主要目的只是用于展示或测试视觉效果,没必要花太多时间去追求内容逻辑的正确。在决定代码实现时,时间成本、需求相关性(必要性)和复杂度都是要纳入考虑的因素。

当然,你的改动的确让这个程序向“完美”更接近了一步,感谢你的反馈。我这几天有事,周三会把这个提议放到”可改进实现“里。如果方便的话,也可以尝试在“可改进实现文件”里修改并提交PR。

AngelLiang commented 6 years ago

是的,从整个项目来看,我也是觉得设计重点及精力不应该放在虚拟数据这里。谢谢您的回复。