Using HarperDB With Django
Tags: django, harperdb
Published: 2022-08-18 17:18:00

Before you try to use HarperDB in your Django project there are some trade offs you should consider. I wanna cover some of these first and then if you still decide HarperDB and Django are a fit, we'll get into the "how to". 

If you're reading this there's a good chance you're coming to this article as a participant of my [August Code Battle Hackathon](https://youtu.be/qU2KfMwOfC4) so I will write with those participants in mind. 

## Tradeoffs

I'll start by saying that at this point in time HarperDB and Django are not exactly suited for each other. Many of the issues are similar to what I said in my [video](https://youtu.be/ORog5kwPd_E) & [article](https://medium.com/@dennisivy/) about why MongoDB and Django are not a fit, but luckily for HarperDB its in a much better position.

With MongoDB the biggest issue is that there is no database driver for Django and there hasn't been a succesful implementation of converting Django queries into NoSQL queries. As a result of this, you lose A LOT of the features Django has built.

HarperDB has a simular issue. There is no database driver at the moment so we run into the same issue we had with MongoDB. In HarperDB's case it's a SQL & NoSQL distributed database so building this driver is not an impossible task. Lets hope they do it soon ;)

Meanwhile, consider the following:

- **No more Django ORM** — With no database adaptor we'll have to use the [HarperDB python package](https://pypi.org/project/harperdb/) instead of the Django ORM.

<br>

- **No More Admin Panel** — Without an adaptor we cant run the proper migrations we need.


- **Database Connection** — The DATABASES connection object in settings.py does nothing for us without a database driver.

<br>

- **No more migrations** — Cant run migrations without a database driver.

<br>

- **Authentication & Models** — This part I am still unsure about. If we are no longer using the Django ORM, how will authentication work with the user model? This part may have to be re-written from scratch.


## My Suggestion

Use FastAPI, Flask or Custom Functions. 

See "[FastAPI + React JS App With HarperDB](https://youtu.be/xwfX70rIxCw) Tutorial"

If you choose to use a lightweight framework you'll have the flexibility you need to make whatever database connection you want. You could also bypass building a backend all together and try using HarperDB [custom functions](https://dev.to/andrewbaisden/how-to-use-harperdb-custom-functions-to-build-your-entire-backend-a2m) to build an API and connect to the database directly from your frontend. 

## How To Guide

[Source code](https://github.com/divanov11/Django-HarperDB-Demo)

I'll assume you already have a HarperDB instance setup with a ready database and a blank Django App ready to go. If not, you can follow me in setting this up in the [video tutorial for this article](https://youtu.be/vxVwjDdSyI4)

### 1 - Install HarperDB Package

You can install the HarperDB python package [here](https://pypi.org/project/harperdb/). This package will give us the tools we'll need to connect to our database and make queries.

```
pip install harperdb
```

### 2 - Connect to Database

Let's make this connection in `settings.py` just above the default `DATABASES` object.

```python
#settings.py
import harperdb

...

DB = harperdb.HarperDB(
    url=<YOUR_HARPERDB_URL>,
    username=<YOUR_HARPERDB_USERNAME>,
    password=<YOUR_HARPERDB_PASSWORD>
)
```

### 3 - Query Database

We'll start accessing data in our views by first importing the `DB` variable from `settings.py` and then accessing data directly.

```python
#views.py
from django.conf import settings

db = settings.DB

def index(request):
    devs = db.search_by_value('hackathon', 'developers', "id", "*", get_attributes=['*'])
    context = {"devs":devs}
    return render(request, 'base/index.html', context)

```

Now to render this data in our template you would treat it like any other queryset passed through our context dictionary.

```html
<ul>
{% for dev in devs %}
      <li>{{dev.name}}</li>
{% endfor %}
</ul>
```

### 4 - Adding CRUD

**Return Single Item**

```python
def dev_profile(request, pk):
    dev = db.search_by_hash('hackathon', 'developers', [pk], get_attributes=['*'])[0]
    context = {"dev":dev}
    return render(request, 'base/profile.html', context)
```

**Creating Items**

```python
from django.shortcuts import render, redirect

#....

def add_profile(request):
    if request.method == 'POST':
        data = request.POST
        db.insert('hackathon', 'developers', [{"name":data['name']}])
        return redirect('index')
    return render(request, 'base/form.html')
```

**Updating Items**


```python
def update_profile(request, pk):
    if request.method == 'POST':
        data = request.POST
        db.update('hackathon', 'developers', [{"id":pk, "name":data["name"]}])
        return redirect('index')

    dev = db.search_by_hash('hackathon', 'developers', [pk], get_attributes=['*'])[0]
    return render(request, 'base/form.html', {"dev":dev})
```

**Deleting Items**


```python
def delete_profile(request, pk):
    if request.method == 'POST':
        db.delete('hackathon', 'developers', [pk])
        return redirect('index')

    dev = db.search_by_hash('hackathon', 'developers', [pk], get_attributes=['*'])[0]
    return render(request, 'base/delete.html', {'dev':dev})
```

And thats it for the demo!