Lesson 6

A Social Blogging Application — Part 5: Followers

Share Tweet

Contents

  1. Resources
  2. Part 5: Followers
    1. Updating the database model
    2. Update the User Profile page
    3. Customize the Blog Posts page
    4. Update the physical database
    5. Conclusion
  3. Exercises
  4. Further Reading

Resources


Part 5: Followers

In this lesson, we will present how to implement the follower feature that allows our users to be able to connect with other users. Along with the follower feature, we also implement another feature that users can see only blog posts on the homepage from the users they follow. The steps to implement the Followers feature are as follows:

  • Update the database model;
  • Update the User Profile model;
  • Customize the homepage.

1/ Updating the database model

In previous lessons, we have structured the database model that supports the one-to-one and one-to-many relationships. In this lesson, we will expand the database structure in order to support a more complex relationship — a many-to-many relationship. The Follower feature is a sort of many-to-many relationship in which a user may follow more than one user, and vice versa. Beyond that, this feature is also a self-referential relationship. In Fig. 1, we show the ERD of the Follower feature, and we can see that both sides of the relationship belong to the same entity. In this case, the left-hand side relationship represents the "followers" relationship, and the other side represents the "followed" relationship.

Fig 1. The “Follows” relationship [2]
Fig 1. The "Follows" relationship [2]

In the "follows" relationship as shown in Fig. 1, we need to store additional information that applies to the link between two entities. We thus add the "date" information to indicate the date a user started following another user. This information also supports ordering lists of followers in a chronological order. We can implement a many-to-many relationship by using an association table which is not as a model and is managed by SQLAlchemy internally - you should refer to Chapter 12 in the textbook [2]. What if we think of this situation in a different way?

Instead of trying to implement the many-to-many relationship in this case, we can decompose this relationship into two one-to-many relationships. In particular, we will construct a new model called Follow which consists of three attributes, i.e., follower_id, followed_id, and timestamp. This idea is also based on the many-to-many relationships in the conceptual view but represented in a different way in the reality view. In Fig. 2, we show the updates to the app/models.py including (i) the implementation of the "Follows" association table as a model and (ii) a many-to-many relationship implemented as two one- to-many relationships.

Fig 2. app/models.py: Update the database model to implement the Follower feature
Fig 2. app/models.py: Update the database model to implement the Follower feature

To understand the code in Fig. 2, I recommend you to refer to Chapter 12 of the textbook [2] where the author has a good explanation of those lines of code.

In Fig. 3, we show the implementation of helper functions in the User model. These functions will allow the application to easily interact with the following-and-followed relationships.

Fig 3. app/models.py: Implement helper functions in User model
Fig 3. app/models.py: Implement helper functions in User model

2/ Update the User Profile page

The User Profile of each user in our application needs to be updated to include either the “Follow” or the “Unfollow” button. The state of this button depends on the current state of relationship between the users. We also need to show the number of and the lists of followers and followed users. Fig. 4 shows the changes to the app/templates/user.html to display the following-and-followed relationships.

Fig 4. app/templates/user.html: Display the following-and-followed relationships
Fig 4. app/templates/user.html: Display the following-and-followed relationships

The updates, as shown in Fig. 4, present four new routes, i.e., /follow/<username>, /unfollow/<username>, /followers/<username>, and /followed_by/<username>. The first route will be invoked when a user clicks on the "Follow" button on another user's profile page, and the implementation is shown in Fig. 5. The implementation of the second route is similar to the first one. The third route is quite difficult to implement, in particular, after validating the requested user, it then paginates the followers relationship. The pagination implementation has been introduced in Lesson 5B. Since the query for followers returns a Follower instance which consists of three attributes as shown in Fig. 2, we need to convert it into a list which has user and timestamp fields in each entry so that rendering on the template is simpler. And the last route, /followed_by/<username>, is almost similar to the third one, but instead of querying the user.follower relationship, we just change to the user.followed. The configuration variable FLASKY_FOLLOWERS_PER_PAGE = 20 must be defined in the config.py before running the application. The template for both of the third and forth routes need to be implemented in a general way, so that it can be reused, in particular, it just receives the data sent from the view functions (followers() and followed_by()) and renders it on the web page, no matter the relationships a user requests. From Fig. 5 to 9, we show the implementations of the four new routes and the followers.html template.

Fig 5. app/main/views.py: Implementation of /follow/<username> route
Fig 5. app/main/views.py: Implementation of /follow/<username> route
Fig 6. app/main/views.py: Implementation of /unfollow/<username> route
Fig 6. app/main/views.py: Implementation of /unfollow/<username> route
Fig 7. app/main/views.py: Implementation of /followers/<username> route
Fig 7. app/main/views.py: Implementation of /followers/<username> route
Fig 8. app/main/views.py: Implementation of /followed_by/<username> route
Fig 8. app/main/views.py: Implementation of /followed_by/<username> route
Fig 9. app/templates/followers.html: Implementation of the followers.html template
Fig 9. app/templates/followers.html: Implementation of the followers.html template

3/ Customize the Blog Posts page

With the implemented Follower feature, we should customize the homepage for authenticated users that renders blog posts from only the users they follow. Therefore, instead of obtaining all blog posts from the database and rendering them on the web page, we now obtain the list of posts by users followed by the current user, the implementation is as shown in Fig. 10. The query in the function has two steps, as follows:

  • First, it joins the Post and Follow models on the condition that Follow.followed_id == Post.author_id.
  • It will then filter all the blog posts that have Follow.follower_id == self.id where self.id identifies the current user.

Fig 10. app/models.py: obtaining followed posts
Fig 10. app/models.py: obtaining followed posts

With the implemented helper function in the User model, the homepage can now give users the ability to view all blog posts or just those from followed users, the implementation is as shown in Fig. 11.

Fig 11. app/main/views.py: Showing all or followed posts
Fig 11. app/main/views.py: Showing all or followed posts

We also implement two new helper functions, as shown in Fig. 11, to set the value of the show_followed variable. You should note that cookies can only be set on a response object, so we need to manually create a response object via the make_response() function. The set_cookie() function takes three parameters, i.e., the cookie's name, the cookie's value, and cookie's lifetime. The max_age parameter indicates the number of seconds until the cookie expires. In this case, we set the lifetime of show_followed cookie is 30 days. By default, if we do not set the max_age parameter, the cookie will expire when the browser is closed.

The homepage template (app/templates/index.html) is updated to include two navigation tabs which represent the /all or /followed routes, the result is as shown in Fig. 12. The source code of the homepage template is shown in Fig. 13.

Fig 12. Display blog posts on homepage [2]
Fig 12. Display blog posts on homepage [2]
Fig 13. app/templates/index.html: Adding tab navigation on homepage
Fig 13. app/templates/index.html: Adding tab navigation on homepage

When you visit the application's homepage and switch to the "Followed" tab, you will notice that your own posts do not appear. Therefore, we need to have a minor update to the source code to render your posts in the "Followed" tab. The simplest way to do this is to register all users as their own followers at the time they create accounts. The implementation is as shown in Fig. 14.

Fig 14. app/models.py: Update the User model to include the self-follow relationship
Fig 14. app/models.py: Update the User model to include the self-follow relationship

4/ Update the physical database

We have a lot of updates to the database model to implement the Follower feature, we thus do update the physical database to include the changes. If the database is small and in the development mode, you can refer to the Running Application section in Lesson 5A. Another way to update the physical database is to implement helper function, as shown in Fig. 15.

Fig 15. app/models.py: Implement helper function to update the physical database
Fig 15. app/models.py: Implement helper function to update the physical database

After implementing the helper function, the database can be updated by running the following scripts in Flask shell:

$ flask shell
>>> User.add_self_follows()


5/ Conclusion

In this lesson, we have discussed the implementation of the Follower feature that allows users to establish a relationship with other users. Based on the relationship, we tweak the homepage to include a navigation tab to filter only blog posts from the following users of the current user. This lesson also presents how to implement the many-to-many relationship and work with cookies in Flask.


Exercises

  1. Update the /user/<username> route and template to render navigation tabs that allows the current user (when he/she visits his/her User Profile page) to read their blog posts or posts from the users they follow.

Further Reading

  1. Many-To-Many Relationship in SQLAlchemy

Next Lesson

In the next lesson, we will implement the last feature of our application - User Comments.

Lesson 7: A Social Blogging Application — Part 6: User Comments


Relaxing 🎧