Welcome to part 4 of my getting started guide. If you missed part 3 you can find it here.
Inside `app.py` lets add user id as a foriegn key.
class Post(db.Model): ... user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
If you have any rows in the post table you'll need to delete them before you can complete the migration.
Windows
# (venv) C:\Users\aipiggy\Documents\blog> flask db migrate -m "Added fk restraint to post" # (venv) C:\Users\aipiggy\Documents\blog> flask db upgrade
Next lets give Post a way to show the user's name when called by adding a relationship that will load the correct record.
class Post(db.Model): ... user = db.relationship('User', backref='user', lazy=True)
And lets update our `templates/blog.html` to include a by line. You can put it where you like, I put it under the post name h1 tag.
<h1>{{ post.name }}</h1> <h3>By {{ post.user.name }}</h3> <p>{{ post.body|safe }}</p>
Now we need to update `app.py` include the user id of the user creating or editing the post.
... if edit_post is None: edit_post = Post(name=request.form["blogName"], slug=request.form["blogSlug"], body=request.form["blogBody"], user_id=current_user.id) db.session.add(edit_post) db.session.commit() return redirect('/admin/blog/' + str(edit_post.id)) else: edit_post.name = request.form["blogName"] edit_post.slug = request.form["blogSlug"] edit_post.body = request.form["blogBody"] edit_post.user_id = current_user.id db.session.add(edit_post) db.session.commit() ...
Lets update the user model to get a list of other posts by this user. Open up `app.py` and edit the User class like so.
class User(UserMixin, db.Model): ... posts = db.relationship('Post', backref='post', order_by='desc(Post.id)', lazy=True))
Note that we are ordering by post id in a decending order here.
To display these we will just have to make a simple loop on `templates/blog.html`. I put it underneith the post body tag.
<p>{{ post.body|safe }}</p> <h4>Other posts by {{ post.user.name }}</h4> <ul> {% for post in post.user.posts[0:5] %} <li><a href="/blog/{{ post.slug }}">{{ post.name }}</a></li> {% else %} <li>None</li> {% endfor %} </ul>
By using an array slice [0:5] we are just showing the first 5 that are returned from the relationship defined on the User class.
Lets fill out the front page and the latest posts from this user parts with a blurb for each post. A blurb is just a short description so it doesn't have to be fancy. We're going to make it plain text in our form and limit to 140 characters. First we update our post model.
Open `app.py` and add the line for blurb
class Post(db.Model): ... blurb = db.Column(db.String(140))
Then migrate
Windows
# (venv) C:\Users\aipiggy\Documents\blog> flask db migrate -m "Added blurb to post" # (venv) C:\Users\aipiggy\Documents\blog> flask db upgrade
Now open `templates/admin/blog.html` and add our form field under the slug.
<div class="form-group"> <label for="blogBlurb">Blog Blurb</label> <input type="text" class="form-control"name="blogBlurb" id="blogBlurb" aria-describedby="blogBlurb" placeholder="Enter blog blurb" maxlength="140" value="{% if post.blurb == None %}{% else %}{{ post.blurb }}{% endif %}"> <small id="blogBlurb" class="form-text text-muted">This should be a quick summary in 140 characters.</small> </div>
Add the field to the edit/create route in `app.py`
if edit_post is None: edit_post = Post(name=request.form["blogName"], slug=request.form["blogSlug"], blurb=request.form["blurb"], body=request.form["blogBody"], user_id=current_user.id) ... edit_post.body = request.form["blogBody"] edit_post.blurb = request.form["blurb"] edit_post.user_id = current_user.id ...
Lets edit `templates/blog.html` to include the blurb first.
<p>{{ post.body|safe }}</p> <h4>Other posts by {{ post.user.name }}</h4> <div class="row"> {% for post in post.user.posts[0:4] %} <div class="col-sm-3"> <a href="/blog/{{ post.slug }}">{{ post.name }}</a><br /> <p>{{ post.blurb }}</p> </div> {% else %} <div class="col-lg-12">This user does not have any other posts.</div> {% endfor %} </div>
The changes to `templates/index.html` will be similar. Under the Welcome message place this code.
<h2>Recent Posts</h2> <div class="row"> {% for post in posts %} <div class="col-sm-12"> <a href="/blog/{{ post.slug }}">{{ post.name }}</a><br /> <p><span class="text-secondary small">{{ post.user.name }}</span><br />{{ post.blurb }}</p> </div> {% else %} <div class="col-lg-12">This user does not have any other posts.</div> {% endfor %} </div>
This is a fairly short article but I think it is worth splitting it off here for the next installment where we set up Apache to run the site.
In our final installment we will set up Apache and WSGI to make our app run in a production environment.