Building an E-Library with  Django and Fauna
Tags: fauna, beginners, python, django
Published: 2021-04-22 16:13:18

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

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

This article will guide you to build a simple electronic library application using the Django web framework and implement the database with Fauna. This e-library would allow authenticated users to add books to the inventory, search for books, and view book details. 

# Prerequisites

To fully understand this tutorial, you are required to have the following in place:


* Python 3.7 or newer.
* Basic understanding of Fauna.
* Basic understanding of Django.
* A text editor.

# Introduction to Fauna

If this is the first time you hear about Fauna, visit my previous article [here](https://dev.to/chukslord1/building-an-appointment-scheduler-app-with-django-and-fauna-2n9o) for a brief introduction.

# Creating The  E-Library Database

To create a Fauna database, you have to first sign up [for an account](https://dashboard.fauna.com/accounts/register?utm_source%3DDevTo%26utm_medium%3Dreferral%26utm_campaign%3DWritewithFauna_ApptScheduler_Ochuku). Suppose you have not done that already. After signing up, you can create a new database by clicking on the `CREATE DATABASE` button on the dashboard.

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

After clicking on the button as shown in the image above, you need to give your database a name and save it.

# Creating The Collections

You need to create two collections in your database; the `Books` collection and the `Users` collection. The `Books` collection will store the documents for all the books added to the e-library. While the `Users` collection will store users data registered on the platform. For the `History days` and `TTL`, use the default values provided and save.

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

# Creating The Indexes

You will create three indexes for your collections; `user`,`book_index`, and `book_index_all`. The `user` index will allow you to scroll through data in the `User` collection. It has one term, which is the `username` field. This term will enable you to match data with the username for easy querying. The username field is unique.

Both `book_index` and `book_index_all` allow you to scroll through data in the `Books` collection. The `book_index` index has one term, which is the `title` field. The `book_index_all` index also has one term, which is the `availability` field.

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

# Creating an API key

To create an API key, go to the security tab on the left side of your dashboard, then click `New Key` to generate a key. You will then be required to provide a database to connect to the key. After providing the information required, click the `SAVE` button.

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

.

Your secret key will be presented as in the image above (hidden here for privacy) after saving your key. Copy your secret key from the dashboard and save it somewhere you can easily retrieve it for later use.

# Building the Django App

Now you will be learning how to implement the various functionalities of the e-library app.

## Cloning the App

Run the code below in your command line to clone the repo containing the Django app on Github.

```
git clone https://github.com/Chukslord1/FAUNA_LIBRARY.git
```

## Importing the  Required Libraries

```python
from django.shortcuts import render,redirect
from django.contrib import messages
from django.http import HttpResponseNotFound
from faunadb import query as q
import pytz
from faunadb.objects import Ref
from faunadb.client import FaunaClient
import hashlib
import datetime
```

## Initializing Fauna Client

To initialize the Fauna client, copy the code below and replace `secret_key` with the API key you created earlier.

```python
client = FaunaClient(secret="secret_key")
```

## The Index Page

```python
def index(request):
   return render(request,"index.html")
```

This page contains all the navigation for the e-library application.

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

## The Login Functionality

```python
def login(request):
   if request.method == "POST":
       username = request.POST.get("username").strip().lower()
       password = request.POST.get("password")

       try:
           user = client.query(q.get(q.match(q.index("user"), username)))
           if hashlib.sha512(password.encode()).hexdigest() == user["data"]["password"]:
               request.session["user"] = {
                   "id": user["ref"].id(),
                   "username": user["data"]["username"]
               }
               return redirect("App:index")
           else:
               raise Exception()
       except:
           messages.add_message(request, messages.INFO,"You have supplied invalid login credentials, please try again!", "danger")
           return redirect("App:login")
   return render(request,"login.html")

```

In the code above, you collected the username and password passed by the user in the POST request. You then made a query to the FQL(Fauna Query Language) client using the username as a match to check if the user exists in the database. If the user exists and the password in the database matches the one passed, you redirect the user to the index page.

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


## The Register Functionality

```python
def register(request):
   if request.method == "POST":

       username = request.POST.get("username").strip().lower()
       email = request.POST.get("email").strip().lower()
       password = request.POST.get("password")

       try:
           user = client.query(q.get(q.match(q.index("user"), username)))
           messages.add_message(request, messages.INFO, 'User already exists with that username.')
           return redirect("App:register")
       except:
           user = client.query(q.create(q.collection("Users"), {
               "data": {
                   "username": username,
                   "email": email,
                   "password": hashlib.sha512(password.encode()).hexdigest(),
                   "date": datetime.datetime.now(pytz.UTC)
               }
           }))
           messages.add_message(request, messages.INFO, 'Registration successful.')
           return redirect("App:login")
   return render(request,"register.html")
```

In the code above, you collected the username, email, and password passed by the user in the POST request. You then check if the username exists in the database by making a query to the FQL client and matching it with the username. If the user does not exist, then an account is created using the fields passed. 

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

## The Add Book Functionality

```python 

def add_book(request):
   if request.method=="POST":
       title= request.POST.get("title")
       genres=request.POST.get("genres")
       summary=request.POST.get("summary")
       pages=request.POST.get("pages")
       copies=request.POST.get("copies")
       author= request.POST.get("author")
       about=request.POST.get("about")
       try:
           book = client.query(q.get(q.match(q.index("book_index"), title)))
           messages.add_message(request, messages.INFO, 'Book Already Exists')
           return redirect("App:add_book")
       except:
           book = client.query(q.create(q.collection("Books"), {
               "data": {
                   "title":title,
                   "genres": genres,
                   "summary": summary,
                   "pages":pages,
                   "copies":copies,
                   "author":author,
                   "about":about,
                   "availability":"True"
               }
           }))
           messages.add_message(request, messages.INFO, 'Book added Successfully')
           return redirect("App:add_book")
   return render(request,"add-book.html")
```

In the code above, you collected the title and other book details passed in the POST request.  You then queried the FQL client to check if the book matching the title passed exists in the database using the `book_index` index. If the book doesn’t exist, then a book is created in the `Books` collection using the details.

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

## The Search Book Functionality

```python

def search_books(request):
   if request.GET.get("search"):
       try:
           search=request.GET.get("search")
           book= client.query(q.get(q.match(q.index("book_index"), search)))["data"]
           context={"book":book}
           return render(request,"search-books.html",context)
       except:
           messages.add_message(request, messages.INFO, 'No book found.')
           return render(request,"search-books.html")
   else:
       try:
           books= client.query(q.paginate(q.match(q.index("book_index_all"), "True")))["data"]
           book_count=len(books)
           page_number = int(request.GET.get('page', 1))
           book = client.query(q.get(q.ref(q.collection("Books"), books[page_number-1].id())))["data"]
           context={"count":book_count,"book":book, "next_page": min(book_count, page_number + 1), "prev_page": max(1, page_number - 1)}
           return render(request,"search-books.html",context)
       except:
           messages.add_message(request, messages.INFO, 'No book found.')
           return render(request,"search-books.html")
```

In the code above, you checked if the user passed a search in the get request. If yes,  you then query the FQL client for books whose title matches the search value using the `book_index` index. However, if the user didn’t create a search, you make a query to the FQL client for books whose availability matches the value “True” using the `book_index_all` index. You then paginated the data retrieved using the pagination method, thus getting the data where the page number passed matches the id of the book in the database.

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

## The Details Functionality

```python
def detail(request,slug):
   try:
       book= client.query(q.get(q.match(q.index("book_index"), slug)))["data"]
       context={"book":book}
       return render(request,"detail.html",context)
   except:
       return render(request,"detail.html")

```

In the code above, you passed slug as an argument that the function expects to pass from the url.  You then query the FQL client using the `book_index` index to get the book whose title matches the slug passed. You then render the particular book to the front-end as context.

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

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

# The App URLs

In the App/urls.py file, you will find the code below:

```python
from django.conf import settings
from django.conf.urls.static import static
from django.urls import path, include
from . import views

app_name = "App"

urlpatterns = [
   path("", views.login, name="login"),
   path("register", views.register, name="register"),
   path("login", views.login, name="login"),
   path("index", views.index, name="index"),
   path("search-books", views.search_books, name="search_books"),
   path("detail/<slug>", views.detail, name="detail"),
   path("add-book", views.add_book, name="add_book"),


]
```

In the code above, you defined all the required urls and connected them to their respective view functions. 

# Conclusion

In this article, you learned how to build an electronic library application with [Fauna's serverless database](https://fauna.com/) and Django. 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 our electronic library application is available on [Github](https://github.com/Chukslord1/FAUNA_LIBRARY). If you have any questions, don't hesitate to contact me on Twitter: [@](https://twitter.com/LordChuks3)[LordChuks3](https://twitter.com/LordChuks3).