Series: Building a Social Network with Flask & Stream — Part 10

Spencer Porter
8 min readApr 12, 2020
Photo by Karl Pawlowicz on Unsplash

This is the tenth installment of a tutorial series focused on how to create a full-stack application using Flask and Stream. In this article, we are going to start styling our app and adding cool new features like notification counts and link previews. Be sure to check out the Github repo to follow along!

Getting Started

As of our last tutorial, we have built all of the basic functionality of our site. Our last hurdle to get over is that the app lacks any kind of aesthetic appeal. Currently, any links that a user adds don’t have any visual flare, and the feeds won’t be winning any UI design awards. One thing that would drastically improve the look of our site would be to add link previews, similar to Facebook, Twitter or Pinterest. Also, being able to auto-populate the title and description fields for the user after they enter a link would make for a much better user experience as well.

Pre-Previews

Luckily for us, Stream provides a very convenient asynchronous JavaScript function that takes a URL and returns all of the information we need using Open Graph. Open Graph protocol returns titles, descriptions, images and videos from a link. As we already have the description and title, the only thing left is images. Feel free (even encouraged) to add a conditional in your own app to allow videos to be displayed instead of the images if they are available.

Before we can start using this functionality though, we need to make space for it in our web app. The first step is adding images to our database model, as well as providing a way for us to update our Stream Feeds for new fields (in app/models.py).

Hindsight Is 20/20

Before we can start adding new content however, if you have created any content already (which based off the last tutorial, you should have), these links don’t have images associated with them yet. When we start using images in our feeds, some will be displayed with images and others will have big, ugly “None” text instead. We need to come up with a way that allows us to update all of the images in the database as well as our Stream feeds. Since we are using Open Graph on the front end, the backend script should use the same thing. To do so, we will be using the Python-OpenGraph library. To install it, run `pip install python-opengraph`. Then (in application.py) we will create a CLI script that returns all content entries in the database, queries their Open Graph values, returning and updating their image values for the table and Stream.

As yet again we have altered our database model, be sure to run `flask db migrate`, `flask db upgrade`, as well as the newly created `flask update-images`. As the command line does not recognize underscores, we replace the underscore(_) with a dash(-) when running the command.

Picture Perfect

Now that everything’s up to date, we can start to change our forms, views and templates for the new field. Starting with the templates (in app/templates/_content.html).

Next, we will need to adjust our index page for the home timeline to retrieve and render the content through the Stream request (in app/templates/index.html).

Finally, we do the same for the collection page (in app/templates/collection.html)

See It To Believe It

We want to give users the chance to see their content before they post it to a collection by creating a link preview in the new content screen. The preview will need to have a few bits of functionality. First, we want it to show and return the image, but we don’t want the image field itself to show. Second, we want the preview to reflect the on-screen input fields for title and description. We’ll start this process off with our forms (in app/main/forms.py)

I added ID parameters to each of the fields in the form, which help us select them using jQuery in the template. I also created the image field as a hidden field so that it won’t be shown to the user.

We also need to update our new content view to both return a token for the user (for the Stream function) as well as be able to use the new image field in creating a record from the form (in app/main/views.py).

Since the preview won’t need or have some of the information provided by the full content template, we will create a new one (in app/templates/_content_preview.html)

The Stream Open Graph scraper works in a very similar way to the requests we’ve been doing for a while, so it’s a rather straightforward crossover for our existing JavaScript code (in app/templates/new_content.html).

The input string variables at the top provide regex for two things. The first is for ‘dirty’ URLs, or when a link is surrounded by unrelated text and the second identifies a ‘clean’ URL, one that doesn’t have any surrounding text.

The addition for this page is the onkeyup and onkeypress methods at the bottom which trigger an update to the preview at the top when the input fields are changed. We will also be using jQuery to set values for the form when the preview function is run , so import it in `app\templates\base.html`.

The last thing we have to do is update the content page itself to include the image (in app/templates/content.html)

Notify Me

While we have a notifications feed running, it doesn’t provide the count of notifications that you would expect from a modern social media site. Luckily for us, it can be put together in a snap. Since the notification count is shown in the navbar, we will create a badge (like our follower count) that displays the count of unseen notifications (in app/templates/base.html).

Since the navbar is returned on every page, we need to provide a current user ID # to the Stream request to get the count. While I personally am going to pass through the current user token on every rendered template, you could just as easily modify the code to use cookies instead.

Finally, we want the count to return to zero once a user opens the notification page, as that would indicate they have in fact seen the notifications. This requires a very simple tweak to accomplish (in app/templates/notifications.html).

Gotta Have Style

We’re getting close to the end now. The last thing we are going to tackle is some simple CSS tweaks to polish the look of the site. Starting off: changing the font. I personally prefer to stick to 1 or 2 fonts at an absolute maximum, as font weight, style and decoration can introduce all the variation you really need. For this demo I chose Montserrat from Google Fonts, but obviously feel free to play around and find what looks best to you. We can import the font in `app/templates/base.html`

Additionally, we have simple text notifying a user they have reached the end of a feed. It would look a lot cleaner if we replaced it to use an image instead. We will have to update this in all the templates that use feeds, so we’ll start with the home page (in app/templates/index.html)

Then notifications (in app/templates/notifications.html)

Next is the user page (in app/templates/user.html)

And finally in the collection page (in app/templates/collection.html)

Profiling

Our User page has some slight stylistic issues, mainly the username and user’s name being displayed right beside each other. As this looks rather redundant, it would be a lot cleaner to set one or the other, with preference being for their actual name. Additionally we’ll add some tags to the page to add styles to them (in app/templates/user.html)

Final Touches

Now all we have to do is put together our CSS for the page, and we’re done!

We’ll start off by creating the CSS document and defining our element level references (in app/static/styles.css).

Next we’ll set a max width on our content container to limit the size of the pictures and nicely center the content (in app/static/styles.css).

After that we’ll provide some visual flair for the content elements, specifically the image. Creating an animated shadow for the image will add a nice effect. Varying the font sizes and weights (don’t go crazy) also helps to break up the text and allows the user to focus on different sections independently (in app/static/styles.css).

Up next is the page headers, as well as our profile and content pages, centering the text and putting emphasis on the user’s name (in app/static/styles.css).

The notifications count has a rather bland gray background, which undercuts its importance. A cool gradient effect will make it a lot more interesting (in app/static/styles.css).

Last but not least, we’ll center and size the “finished” image we integrated this week (in app/static/styles.css).

Final Thoughts

Congratulations!

You have officially created an entire web application with Flask and Stream, complete with styling and some rather slick functionality. The response times for our content is seamless thanks to lightning quick data retrieval from Stream, with a modern feed based view to check out all the latest and greatest activities from your friends. We are getting very close to the end of this section of the tutorial, with our last step being deployment and configuration. In the next article, I am going to take you through deploying the entire app as a serverless function using AWS Lambda, RDS, and Amazon Mail!

As always, thanks for reading and happy coding!

--

--