Well, I can’t put it off any longer. It’s time to add the final large feature of this app: the account system. I decided to implement a system for accounts that closely resembles the one implemented in this tutorial series, which is what I originally learned to teach myself Flask. I went back through it and reviewed the relevant lessons (plus looked at my example project that I made from those tutorials) to prepare for this implementation.
I started off by creating two new forms, one for registering new accounts, and one for logging in. I saved these in a new forms.py folder in my account blueprint (which is what I renamed the user blueprint).
Then, I created a “register” route and a “login” route, using placeholder code for what would happen if the forms actually validated:
I then created two new links for the navbar, one to register and one to log in:
Then I wrote the first draft of the template for the register page, which is pretty much just the registration form that I’d already made.
I added a small amount of CSS to the .centered-form class to center it and keep it a certain size, and the result is a nice clean registration page:
I’ll spare you the code for the “login” template, as it’s essentially the exact same, just with fewer form fields. Here’s what it looks like in practice, though:
Of course, none of these boxes actually do anything because I have no way to create or keep track of users. It’s time to change that. I returned to my models.py file and created a new database model for users:
In following with the original tutorial, I decided to use bcrypt to encrypt the passwords. I wrote in the necessary code in the register and login routes to create a new account and log the user in:
Finally, I created a logout route that would log the user out:
Now I had a basic login capability implemented. But I wasn’t quite finished with this section; I wanted to provide a little bit more user feedback for if the registration went awry, and I wanted to only show the option to register if no one was logged in.
First, I redesigned the template so that it would only display the options to register/login if the user wasn’t logged in, and would display the name of the logged in user. I also added the “Logout” button to the dropdown menu, at the end, and set it to only appear if the user was logged in.
Here’s what the dropdown menu looks like when logged in:
Then, I returned to my template pages, and rewrote them so that they would show errors that caused prevented the form from validating:
With the help of a little CSS, this shows the errors for validation nicely:
This isn’t perfect, though. For example, it can’t show database errors, such as what would happen if the user tried to enter in a username that had already been used. To solve that, I returned to my routes and added a try/except block:
This works well enough, although I don’t really like that it uses flash() for some errors and displays the others underneath the form. That’s something I’d like to come back to later, but this post is getting long, and I think I’m going to end it here. I’m updating the github repo for this code, so if you’re curious on the details, you can check it out here.
Next Steps:
link each grocery list to an account and make sure that the user can only see their lists