What you’ll be making

You will be making a library management system. In this system, there will be librarians, patrons, and books.

Here’s a video demonstrating my implementation:

Your task

  1. Click the GitHub link in the project 3 announcement, and clone your proj3 repo like before.
  2. Go into that directory and run the Flask app there to test that it works (see below).
  3. Edit the Python and template code to make your app.
    • And feel free to style it up with CSS any way you like.

The starting point

After cloning the starter repo, be sure to test that you have everything set up right:

You have been given a few files:


User accounts

The starting code is based on the “Minitwit” example I gave you and showed in class. It already handles the ability for users to sign in, log out, and for patrons to sign themselves up.

In models.py, the initdb command creates a single user, owner, with the password pass.

The only way to create librarian accounts is for a logged-in librarian to create it. Librarians cannot sign themselves up.

Within your Python code and templates, the g.user variable will be a User object containing the currently logged-in user, or it will be None. This is set up by the before_request function in proj3.py.

You can therefore tell whether or not the current user is a librarian with g.user.librarian.


/ (the home page)

This is the home.html template, and the accompanying home() function in proj3.py.

This page will list the books in the library:

This page will also look a little different for each kind of visitor:


Borrowing and returning books

Since these actions change the state of the server, the buttons for these should send POST requests. However, you can’t make a POST request with a regular <a> link.

Instead, you must put each button inside a <form> element, and each button should be a <button type="submit"> element. The code for each button might look like:

<form method="post">
    <button type="submit" name="book_id" value="2">Return this book</button>
</form>

Your template will generate this code for each button in the listing.

Your home() function in proj3.py will detect POST requests, and if so, get the book ID by looking up request.form.get('book_id'). (Have a look at the login() function for an example on doing this. The get() method will not crash if there is no book_id, it will just give None.)

Last, you can change which books a user is borrowing with their .borrows attribute:

    someBook = # ...some code that gets a Book object...
    g.user.borrows.append(someBook) # to borrow
    g.user.borrows.remove(someBook) # to return

Hey, if you got this far, that means you’re done with the patron stuff, and have a 70%. Great!


Librarian mode

For librarians, you will add some extra navigation items to base.html, inside the <nav>’s <ul>:

For the home page:

Note: I guess you could still allow librarians to borrow books, just like patrons… But if it looks too cluttered, you don’t have to.


The /books/<book_id> page

Make a new route function using the above route, like this:

@app.route('/books/')
@app.route('/books/<book_id>')
def books(book_id=None):
    ...

This page is librarian-only. If a non-librarian is logged in, or no user is logged in, redirect them to the home page.

This page has two modes:

If book_id is invalid, you should abort with a 404.


The /accounts/<user_id> page

One last page. This will be similar to the /books/ page.

This page is librarian-only. If a non-librarian is logged in, or no user is logged in, redirect them to the home page.

This page has two modes: