Series: Building a Social Network with Flask & Stream – Part 5

This is the fifth installment of a tutorial series focusing on how to create a full-stack application using Flask and Stream. In this article will go through setting up a customizable user profile page and an introduction to adding content in Stream, we’ll even toss in a brief section on making a testing module to make sure everything is working properly. Be sure to check out the Github repo to help you follow along!

Getting Started

To start off, we will create a user.html template file. Initially, this will return just a user’s username and gravatar and, if you are an admin, the user’s email address. Don’t worry too much about the lack of information just yet, we’re going to be adding in more fields as we go along:

app/templates/user.html

Jinja and Data Flow

Meet Jinja: you can see in the file we just created some curly-braces containing a conditional. Jinja gives us a template that allows us to conditionally render a fields flow control, and we are going to be taking advantage of that capability as we go along.

Most of the rest of the file should seem pretty straightforward after that; we are going to pass through a user object with the render_template response, like in our earlier forms, in order to populate the name, gravatar and email fields.

Now that we have our template, let’s set up the route to return it:

app/main/views.py

In the views route, we are taking the username as a variable through the URL path and passing it to the route function. The username is then used as a filter in a query of the User class, which returns a 404 response if the user isn’t found. If the user is found, the function renders the user.html template, passing through the user object to populate the fields of the page.

Getting There

Next, we’ll provide a way for a user to access the page from within the site by adding a profile link to the navbar:

app/templates/base.html

Forms on Forms

Beautiful! Now you can view your profile page, and navigate there easily using the navbar. But I would hardly blame anyone for calling the info sparse. For that reason, we should add a little depth to it by allowing users to edit and add more information, should they so choose. For this, we will have to dive back into forms again:

app/main/forms.py

Field Day

As you may have noticed, I added a name field to the “edit profile” form. This means that we will have to update our database model to reflect this new field:

app/models.py

Upgrades People, Upgrades

Since we have updated our User model, we now have a great opportunity to update our database using [alembic](https://flask-migrate.readthedocs.io/en/latest/). The commands are pretty basic:

The migrate command generates a migration script (be sure to always double-check the file to ensure it’s correct), which is then applied with upgrade.

Routed

Now that we have the database up-to-date with the new field, it’s time to set up our routes and template to return the forms. Since the core of the template will stay the same, and only the fields will change, we can create one “edit profile” page for both users and admins, and simply change the form that is provided:

app/main/views.py

app/templates/edit_profile.html

Last, but not least, we’ll need to create a link on the user page to allow users to edit their profiles, as well as one for admins to do the same. While we do this, we can also show the updated fields using conditionals:

app/templates/user.html

The result of these changes should give you something like this:

Next Steps

Now that we are finished with our user profile pages (for now), we’ll start to put together a testing module to ensure that the critical functions of our site work properly. In the very top directory of our project, we will create a new directory named “tests”. Within that, create a new __init__.py file, which we will leave blank, as well as a test_basics.py file, and a test_user_model.py file and fill them out like so:

tests/test_basics.py

tests/test_user_model.py

The tests above should seem pretty self-explanatory, given their function names. Essentially, each one runs through a specific aspect of the app itself or the User model and its functions, testing to make sure that everything is working as it should. The goal when designing tests is to ensure that every function that you use in a site is properly validated and operating the way you designed it to.

Our last task is to create a CLI task that will allow you to run your tests. Opening up our application.py file, use the code that follows:

application.py

Now, you can run tests through the command line with “flask test”, returning a function-by-function review, along with any errors. Make sure that all the tests return okay and then you’re finished!

Testing The Waters

Over the past five articles we have gone through the creation of the basics in web app development: creating/updating users, project file structure, testing, database migrations, and email, to get us ready to implement more advanced functionality. Next week we will be getting into the real meat of the project, allowing users to create their own collections and managing them effectively. Before we get there though, I would recommend that you play around with the Stream-Python library. As we get further into the project, having a little experience can go a long way in understanding how it all fits together, and how you can create your own projects using this awesome tool!

Bonus Round

I am going to take a few minutes to run through some basic functions outside of the scope of our project to give you an idea of how it works. As always, I recommend that you boot up a venv (python “virtual environment”) to keep your packages isolated from the rest of your development environment.

Opening up a new Python project with an active virtual environment, pip install the stream-python library:

Next, either create a new Python file or open a Python terminal, and import the Stream package at the top, instantiating a new client using your API keys found here. Be sure to create a new app in Streamfor this test, as you don’t want to potentially mix data from the test with the rest of our project. We are going to use the “flat feed” type, which I’ve titled ‘user’ for this demo:

test.py

In the feed object, you can see two strings: the first is the feed type that we are using (user), and the second is a user ID. You can use any string you want to represent a user, just make sure that it is unique, you don’t want to have two overlapping IDs. Now that we have created a user feed, we can start adding activities to it with the aptly named add_activity() function. This function takes in the actor (who is doing the activity), the verb (like pin, tweet, or post), the object (the id of the tweet, pin or post in your database), and any other custom fields that you wish to put in there (like a copy of the message itself):

test.py

Next, we’ll create a second user, and have it follow our first, in order to try out retrieving activities:

test.py

Running this script, you should see a JSON response with a list of dictionaries, including all of the previous activities of the followed user:

One thing to note in the response object is the ID string, using this we will be able to edit a post, delete it, or quickly paginate through activities (which comes in handy for infinite scroll). As such, note that when you upload activities in your own projects, as well as our own later, we are handling the response object when we add an activity and storing it in our own database.

Final Thoughts

Now you have tried out some very basic functionality with Stream, but there is a lot more that we will get into over the course of this project (and a lot that we won’t get to). Once again, I encourage you to play around with the library and check out the documentation to get comfortable using it.

Thanks for reading and happy hacking!

Note: The next post in this series can be found here.