---
title: Build a CRUD Web App With Python and Flask - Part Two
source: https://www.digitalocean.com/community/tutorials/build-a-crud-web-app-with-python-and-flask-part-two
---
This tutorial is out of date and no longer maintained.
### [Introduction](#introduction)
This is Part Two of a three-part tutorial to build an employee management web app, named Project Dream Team. In [Part One](https://www.digitalocean.com/community/tutorials/build-a-crud-web-app-with-python-and-flask-part-one) of the tutorial, we set up a MySQL database using MySQL-Python and Flask-SQLAlchemy. We created models, migrated the database, and worked on the `home` and `auth` blueprints and templates. By the end of Part One, we had a working app that had a homepage, registration page, login page, and dashboard. We could register a new user, log in, and log out.
In Part Two, we will work on:
1. Creating an admin user and admin dashboard
2. Creating, listing, editing, and deleting departments
3. Creating, listing, editing, and deleting roles
4. Assigning departments and roles to employees
## [Admin User](#admin-user)
We’ll start by creating an admin user through the command line. Flask provides a handy command, `flask shell`, that allows us to use an interactive Python shell for use with Flask apps.
```
Output
>>> from app.models import Employee
>>> from app import db
>>> admin = Employee(email="admin@admin.com",username="admin",password="admin2016",is_admin=True)
>>> db.session.add(admin)
>>> db.session.commit()
```
We’ve just created a user with a username, `admin`, and a password, `admin2016`. Recall that we set the `is_admin` field to default to `False` in the `Employee` model. To create the admin user above, we override the default value of `is_admin` and set it to `True`.
## [Admin Dashboard](#admin-dashboard)
Now that we have an admin user, we need to add a view for an admin dashboard. We also need to ensure that once the admin user logs in, they are redirected to the admin dashboard and not the one for non-admin users. We will do this in the `home` blueprint.
app/home/views.py
app/auth/views.py
Next, we’ll create the admin dashboard template. Create an `admin_dashboard.html` file in the `templates/home` directory, and then add the following code to it:
app/templates/home/admin_dashboard.html
Now we need to edit the base template to show a different menu for the admin user.
app/templates/base.html
In the menu above, we make use of the `current_user` proxy from Flask-Login to check whether the current user is an admin. If they are, we display the admin menu which will allow them to navigate to the Departments, Roles, and Employees pages. Notice that we use `#` for the links in the admin menu. We will update this after we have created the respective views.
Now run the app and log in as the admin user that we just created. You should see the admin dashboard:
Let’s test the error we set in the `home/views.py` file to prevent non-admin users from accessing the admin dashboard. Log out and then log in as a regular user. In your browser’s address bar, manually enter the following URL: `http://127.0.0.1:5000/admin/dashboard`. You should get a `403 Forbidden` error. It looks pretty boring now, but don’t worry, we’ll create custom error pages in Part Three!
## [Departments](#departments)
Now we’ll start working on the `admin` blueprint, which has the bulk of the functionality in the application. We’ll begin by building out CRUD functionality for the departments.
### [Forms](#forms)
We’ll start with the `admin/forms.py` file, where we’ll create a form to add and edit departments.
app/admin/forms.py
The form is pretty simple and has only two fields, `name` and `department`, both of which are required. We enforce this using the `DataRequired()` validator from WTForms. Note that we will use the same form for adding and editing departments.
### [Views](#views)
Now, let’s work on the views:
app/admin/views.py
We begin by creating a function, `check_admin`, which throws a `403 Forbidden` error if a non-admin user attempts to access these views. We will call this function in every admin view.
The `list_departments` view queries the database for all departments and assigns them to the variable `departments`, which we will use to list them in the template.
The `add_department` view creates a new department object using the form data and adds it to the database. If the department name already exists, an error message is displayed. This view redirects to the `list_departments`. This means that once the admin user creates a new department, they will be redirected to the Departments page.
The `edit_department` view takes one parameter: `id`. This is the department ID and will be passed to the view in the template. The view queries the database for a department with the ID specified. If the department doesn’t exist, a `404 Not Found` error is thrown. If it does, it is updated with the form data.
The `delete_department` view is similar to the `edit_department` one, in that it takes a department ID as a parameter and throws an error if the specified department doesn’t exist. If it does, it is deleted from the database.
Note that we render the same template for adding and editing individual departments: `department.html`. This is why we have the `add_department` variable in the `add_department` view (where it is set to `True`), as well as in the `edit_department` view (where it is set to `False`). We’ll use this variable in the `department.html` template to determine what wording to use for the title and heading.
### [Templates](#templates)
Create a `templates/admin` directory, and in it, add a `departments` directory. Inside it, add the `departments.html` and `department.html` files:
app/templates/admin/departments/departments.html
We’ve created a table in the template above, where we will display all the departments with their name, description, and the number of employees. Take note of the `count()` function, which we use in this case to get the number of employees. Each department listed will have an edit and delete link. Notice how we pass the `department.id` value to the `edit_department` and `delete_department` views in the respective links.
If there are no departments, the page will display “No departments have been added”. There is also a button that can be clicked to add a new department.
Now let’s work on the template for adding and editing departments:
app/templates/admin/departments/department.html
Notice that we use the `add_department` variable which we initialized in the `admin/views.py` file, to determine whether the page title will be “Add Department” or “Edit Department”.
Add the following lines to your `style.css` file:
app/static/css/style.css
The `.middle`, `.inner`, and `.outer` classes are to center the content in the middle of the page.
Lastly, let’s put the correct link to the Departments page in the admin menu:
Re-start the flask server, and then log back in as the admin user and click on the Departments link. Because we have not added any departments, loading the page will display:
Let’s try adding a department:
It worked! We get the success message we configured in the `add_department` view, and can now see the department displayed.
Now let’s edit it:
Notice that the current department name and description are already pre-loaded in the form. Also, take note of the URL, which has the ID of the department we are editing.
Editing the department is successful as well. Clicking the Delete link deletes the department and redirects to the Departments page, where a confirmation message is displayed:
## [Roles](#roles)
Now to work on the roles. This will be very similar to the departments code because the functionality for roles and departments is exactly the same.
### [Forms](#forms)
We’ll start by creating the form to add and edit roles. Add the following code to the `admin/forms.py` file:
app/admin/forms.py
### [Views](#views)
Next, we’ll write the views to add, list, edit, and delete roles. Add the following code to the admin/views.py file:
app/admin/views.py
These list, add, edit, and delete views are similar to the ones for departments that we created earlier.
### [Templates](#templates)
Create a `roles` directory in the `templates/admin` directory. In it, create the `roles.html` and `role.html` files:
app/templates/admin/roles/roles.html
Just like we did for the departments, we have created a table where we will display all the roles with their name, description, and the number of employees. Each role listed will also have an edit and delete link. If there are no roles, a message of the same will be displayed. There is also a button that can be clicked to add a new role.
app/templates/admin/roles/role.html
We use the `add_role` variable above the same way we used the `add_department` variable for the `department.html` template.
Once again, let’s update the admin menu with the correct link:
app/templates/base.html
Re-start the server. You should now be able to access the Roles page, and add, edit and delete roles.
## [Employees](#employees)
Now to work on listing employees, as well as assigning them departments and roles.
### [Forms](#forms)
We’ll need a form to assign each employee a department and role. Add the following to the `admin/forms.py` file:
app/admin/forms.py
We have imported a new field type, `QuerySelectField`, which we use for both the department and role fields. This will query the database for all departments and roles. The admin user will select one department and one role using the form on the front-end.
## [Views](#views)
Add the following code to the `admin/views.py` file:
app/admin/views.py
The `list_employees` view queries the database for all employees and assigns them to the variable `employees`, which we will use to list them in the template.
The `assign_employee` view takes an employee ID. First, it checks whether the employee is an admin user; if it is, a `403 Forbidden` error is thrown. If not, it updates the `employee.department` and `employee.role` with the selected data from the form, essentially assigning the employee a new department and role.
## [Templates](#templates)
Create a `employees` directory in the `templates/admin` directory. In it, create the `employees.html` and `employee.html` files:
app/templates/admin/employees/employees.html
The `employees.html` template shows a table of all employees. The table shows their full name, department, and role, or displays a `-` in case no department and role has been assigned. Each employee has an assigned link, which the admin user can click to assign them a department and role.
Because the admin user is an employee as well, they will be displayed in the table. However, we have formatted the table such that admin users stand out with a green background and white text.
app/templates/admin/employees/employee.html
We need to update the admin menu once more:
app/templates/base.html
Navigate to the Employees page now. If there are no users other than the admin, this is what you should see:
When there is an employee registered, this is displayed:
Feel free to add a variety of departments and roles so that you can start assigning them to employees.
You can re-assign departments and roles as well.
## [Conclusion](#conclusion)
We now have a completely functional CRUD web app! In Part Two of the tutorial, we’ve been able to create an admin user and an admin dashboard, as well as customize the menu for different types of users. We’ve also built out the core functionality of the app, and can now add, list, edit, and delete departments and roles, as well as assign them to employees. We have also taken security into consideration by protecting certain views from unauthorized access.
In Part Three, we will create custom error pages, write tests, and deploy the app to [PythonAnywhere](https://www.pythonanywhere.com/).