•February 6th 2020
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!
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:
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:
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.
Next, we’ll provide a way for a user to access the page from within the site by adding a profile link to the
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
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:
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:
migrate command generates a migration script (be sure to always double-check the file to ensure it’s correct), which is then applied with
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:
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:
The result of these changes should give you something like this:
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:
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:
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!
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
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:
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):
Next, we’ll create a second user, and have it follow our first, in order to try out retrieving activities:
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.
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.