[models.py]

class User(UserMixin, Model):
    ....
    def get_stream(self):
        return Post.select().where( 
            (Post.user << self.following()) |
            (Post.user == self)
            )

    def following(self):
    ....

Post.select().where( (Post.user << self.following( ))  |  (Post.user == self) )
Select all posts, where either the post user in inside the following query, OR the post user is current user.

 

[app.py]

@app.route('/stream/')
def stream(username=None):
  ...

@app.route('/post/<int:post_id>')
def view_post(post_id):
    if post_id:
        posts = models.Post.select().where( models.Post.id==post_id )
        return render_template('stream.html', stream=posts)

posts = models.Post.select().where(models.Post.id==post_id)
We could have used Post.get on this one to get the one record of the requested post, and viewed it on a a new template. But in order to do DRY programming, we cheated a little in order to use the stream.html template again, and returned a query to the template that has one record as the stream.
[stream.html]

... </time> <a href="{{ url_for('view_post', post_id=post.id) }}" class="view">View</a> ...

We must of course update the View Post link in the stream.html template, nothing new here.