Building a Debt Tracker with Python and Fauna
Tags: fauna, serverless, python, webdev
Published: 2021-05-18 15:18:09

Written in connection with the [Write with Fauna](https://fauna.com/blog/write-with-fauna) program.

This article focuses on exploring Fauna’s CRUD capabilities to build a Python web application for managing debts. We will be creating a debt manager that provides functionalities for keeping track of debts users have incurred using Python and Flask.

[Fauna](https://dashboard.fauna.com/accounts/register?utm_source=DevTo&utm_medium=referral&utm_campaign=WritewithFauna_DebtTracker_SEsenyi) is a flexible, developer-friendly, transactional cloud database delivered as a secure Data API that provides two interfaces: GraphQL and the Fauna Query Language (FQL). It includes functionality to store collections, indexes, and other databases (multi-tenancy). To learn more about Fauna, visit the [official documentation](https://docs.fauna.com/fauna/current/start/index.html).

> Note: The rest of this article assumes you have a fair understanding of Fauna, Python, and Flask. For an in-depth tutorial on serverless databases and Fauna, check out my [Fauna intro tutorial](https://dev.to/lordghostx/building-a-telegram-bot-with-python-and-fauna-494i) first.

# Setting Up the Fauna Database

## Create the Fauna Database

We need to create the database for the debt manager in Fauna’s dashboard. If you have not created an account on Fauna before now, create one on [Fauna’s website.](https://dashboard.fauna.com/accounts/register?utm_source=DevTo&utm_medium=referral&utm_campaign=WritewithFauna_DebtTracker_SEsenyi)

In the dashboard, click on the `NEW DATABASE` button, provide a name for the database then press the `SAVE` button.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6vk25tt0jyw8clz0usqk.png)

## Create the Database Collections

Now, we need to create a Fauna collection to store data collected in the recently created database. A collection is similar to SQL tables containing similar characteristics, e.g., a user collection with information about users in the database.

To create a collection:

* navigate to the `Collections` tab on the Fauna sidebar (left side of the screen)
* click on the `NEW COLLECTION` button
* provide a name for the collection
* press the `SAVE` button

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3bhsp62dw7b0t0juxqhb.png)

## Create the Collection Indexes

We need to create an index for the collection of the database. A Fauna index allows us to browse through data stored in a database collection based on specific attributes.

To create an index:

* move to the `Indexes` tab on the Fauna sidebar (left side of the screen)
* click on the `NEW INDEX` button and provide the necessary information
* press the `SAVE` button.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/649i3xv9dkh3c39as0vv.png)

## Generate Database Security Key

Finally, we need to create a `Security Key` to connect the database to the application. Go to the `Security` tab on the Fauna sidebar (left side of the screen), click the `NEW KEY` button, provide the necessary information, and then press the `SAVE` button.

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mq56wjjxkmys1enpkr3c.png)

Once you have done this, Fauna will present you with your `Secret Key`. Copy the key immediately and store it somewhere easily retrievable because it will only be displayed once.

# Downloading the Demo Application

## Clone the Project Repository

For the sake of convenience, I have written a Flask application with a Bootstrap user interface that we will use in this article. To get started, we need to clone [my repository](https://github.com/LordGhostX/fauna-debt-tracker) and initialize the application like so:

```bash
git clone https://github.com/LordGhostX/fauna-debt-tracker   
cd fauna-debt-tracker
```

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3yimbq7ins229gcuumku.png)

## Install the Project Requirements

We need to install the external libraries required by the application before we can run it. In the terminal, type:

```bash
pip install -r requirements.txt
```

Finally, run the application to make sure it’s working. In the terminal, type:

```bash
python3 app.py
```

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yeixohtlr4fjccan8rr.png)

## Configuring the Project Settings

To configure the project, open the `app.py` file and replace the `FAUNA_SECRET_KEY` placeholder variable with the `Security Key` generated earlier. You can also change the application’s `SECRET KEY` or fetch these values using [environment variables](https://www.askpython.com/python/environment-variables-in-python).

![](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qksvf917t4b9hti4lg0t.png)

# Integrating Fauna into Python and Flask

For the debt manager, we will explore the four basic operations of persistent storage, Create (C), Read (R), Update (U), and Delete (D), using Fauna.

## Creating New Documents in Fauna

In our `add_loan` route, we used Fauna’s [Create](https://docs.fauna.com/fauna/current/api/fql/functions/create) function to store the collected loan data in our database’s `loans` collection.

```python
@app.route("/loans/add/", methods=["POST"])
def add_loan():
    name = request.form.get("name")
    amount = request.form.get("amount")
    date = request.form.get("date")

    loan_data = client.query(
        q.create(
            q.collection("loans"), {
                "data": {
                    "name": name,
                    "amount": float(amount),
                    "pending": True,
                    "date_created": datetime.strptime(date, "%Y-%m-%d").astimezone(tz=tz.tzlocal())
                }
            }
        )
    )

    flash("You have successfully added loan information!", "success")
    return redirect(url_for("loans"))
```

> The `Create` function adds a new document to a collection. It takes a `collection_ref` parameter which indicates what collection we should create the document, and a `param_object` parameter which contains the document data and optional metadata.

## Reading Documents from Fauna

In our `loans` route, we used Fauna’s [Paginate](https://docs.fauna.com/fauna/current/api/fql/functions/paginate) function to retrieve the [references](https://docs.fauna.com/fauna/current/api/fql/types#ref) of stored loans in our database, then the [Get](https://docs.fauna.com/fauna/current/api/fql/functions/get) function to query the data of each document with their `Reference`.

```python
@app.route("/loans/")
def loans():
    loans = client.query(
        q.paginate(
            q.match(q.index("loans_by_pending"), True),
            size=100_000
        )
    )
    loans_data = [
        q.get(
            q.ref(q.collection("loans"), loan.id())
        ) for loan in loans["data"]
    ]
    return render_template("loans.html", loans_data=client.query(loans_data))
```

## Updating Documents in Fauna

In our `update_loan` route, we used Fauna’s [Update](https://docs.fauna.com/fauna/current/api/fql/functions/update) function to update the loan amount of documents in our collection. The `Update` function takes a `Reference` parameter which indicates the document to be updated, and a `param_object` parameter which contains the document data to update.

```python
@app.route("/loans/update/", methods=["POST"])
def update_loan():
    action = request.form.get("action")
    amount = request.form.get("amount")
    loan_id = request.form.get("loanID")

    loan_data = client.query(
        q.get(
            q.ref(q.collection("loans"), int(loan_id))
        )
    )

    old_amount = loan_data["data"]["amount"]
    if action == "Borrow More":
        new_amount = old_amount + float(amount)
    elif action == "Repay Loan":
        new_amount = old_amount - float(amount)

    client.query(
        q.update(
            q.ref(q.collection("loans"), int(loan_id)), {
                "data": {
                    "amount": new_amount
                }
            }
        )
    )

    flash("You have successfully updated loan information!", "success")
    return redirect(url_for("loans"))
```

## Deleting Documents from Fauna

In our `clear_loan` route, we used Fauna’s [Delete](https://docs.fauna.com/fauna/current/api/fql/functions/delete) function to delete a document from the database with a specified `Reference`. The `Delete` function removes a document. This includes user-created documents, plus system documents for `Collections`, `Indexes`, `Databases`, etc.

```python
@app.route("/loans/clear/<int:loan_id>/")
def clear_loan(loan_id):
    client.query(
        q.delete(
            q.ref(q.collection("loans"), loan_id)
        )
    )

    flash("You have successfully cleared loan information!", "success")
    return redirect(url_for("loans"))
```

# Conclusion

In this article, we built a debt tracker with Fauna's serverless database and Python. We saw how easy it is to integrate Fauna into a Python application and got the chance to explore some of its core features and functionalities.

The source code of the debt manager is available on [GitHub](https://github.com/LordGhostX/fauna-debt-tracker). If you have any questions, don't hesitate to contact me on Twitter: [@LordGhostX](https://twitter.com/LordGhostX)