How To Populate Your Database From An External API in Django.
Tags: python, django, api, codenewbie
Published: 2020-11-18 10:54:30

In today's writeup, I am going explain how to populate your database with data from an external API in Django by building a small project. For this, We are going to use the MealDB API - `https://www.themealdb.com/api.php` and also bootstrap for the styling.

First, create a new project and your virtual environment.

```python
django-admin startproject meal_project
```

Change into the project directory and create a new app:

```python
cd meal_project
python manage.py startapp meal_app

```

Add the newly created app into installed apps under 'settings.py' 

```python
INSTALLED_APPS = [
'meal_app',
]
```

In the root directory, create a 'templates' folder and add it within 'settings.py'

```python
TEMPLATES = [
 'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
```

In meal_app, create a 'urls.py' file and within the 'meal_project' urls.py file, include the path to the meal_app 's  urls.py file.

```python
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include ('meal_app.urls'))
]
```

In meal_app.urls, add the path to our views. Within our views, we going to have a list view and a detail view.

```python
from django.urls import  path
from product_app import views

urlpatterns = [
    path('', views.get_meals, name = "get_meals"),
    path('meals/<int:id>/',views.meal_detail, name = "meal_detail")
]
```

In templates folder, create a 'meals' folder and within it a 'base.html' from which all other templates will inherit. 

`base.html`:

```html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Movie App</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
{% block content%}
{% endblock %}
   
<script src = "{% static 'js/script.js' %}"></script>
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.min.js" integrity="sha384-w1Q4orYjBQndcko6MimVbzY0tgp4pWB4lZ7lr30WKz0vr/aWKhXdBNmNb5D92v7s" crossorigin="anonymous"></script>
</body>
</html>
```

Then `meal.html` 

```html
{% extends 'meals/base.html'%}
{% load static %}
{% block content %} 
    <div class = "container">
      <br>
      <h2 class = "text-center">Search for your favorite Meals</h2> 
      <br>
      <form method="GET">
        <input type = "text" name = "name" placeholder="Search..." class = "text-center">
        <button type = "submit" class = "btn-danger btn-sm">SEARCH MEAL</button>
      </form> 
    </div>  
{% endblock %}

```


The `meal.html` contains a simple search form and a submit button.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/g0o2bhshr3zgniwo6o38.png)

Next, we need to create a model which we would populate with data from the meal DB API. The fields on the model correspond to the specific attributes on the API that we want to populate our database with.

`models.py`

```python
from django.db import models

class Meal(models.Model):
    name = models.CharField(max_length=50, blank = True, null = True)
    category = models.CharField(max_length=10, blank = True, null = True)
    instructions = models.CharField(max_length=4000, blank = True, null = True)
    region = models.CharField(max_length=20, blank = True, null = True)
    slug = models.SlugField(default = 'test')
    image_url = models.CharField( max_length=50, blank = True, null = True)

    def __str__(self):
        return self.name
```

What our API looks like:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/r3ausf2s2eick7w7p4yd.png)

It's now time to migrate our database and create our database tables.

```python
python manage.py makemigrations
python manage.py migrate
```

Next, we need to install a python library that helps in making HTTP requests;

```python
pip install requests
```

The main logic of the project will reside in the `views.py`.

```python
from django.shortcuts import  render
from meal_app.models import Meal
import requests

def get_meals(request):
    all_meals = {}
    if 'name' in request.GET:
        name = request.GET['name']
        url = 
        'https://www.themealdb.com/api/json/v1/1/search.php? 
        s=%s' % name
        response = requests.get(url)
        data = response.json()
        meals = data['meals']
       
        for i in meals:
            meal_data = Meal(
                name = i['strMeal'],
                category = i['strCategory'],
                instructions = i['strInstructions'],
                region = i['strArea'],
                slug = i['idMeal'],
                image_url = i['strMealThumb']
            )
            meal_data.save()
            all_meals = Meal.objects.all().order_by('-id')

    return render (request, 'meals/meal.html', { "all_meals": 
    all_meals} )

```

In the function `get_meals` defined above, we obtain the value the user types into the search input using `request.GET` and assign it to a variable `name`.Then we pass this variable as our search term into the url when we make the HTTP request. We get a response and convert it JSON. This returns a list which we save in the variable `meals`.

```python
name = request.GET['name']
url = 'https://www.themealdb.com/api/json/v1/1/search.php?s=%s' % name
response = requests.get(url)
data = response.json()
meals = data['meals']
```

Now in order to populate our database with the list our HTTP request returned, we need to loop through the list items and assign the parameters as fields in our model.

```python
 for i in meals:
            meal_data = Meal(
                name = i['strMeal'],
                category = i['strCategory'],
                instructions = i['strInstructions'],
                region = i['strArea'],
                slug = i['idMeal'],
                image_url = i['strMealThumb']
            )
            
```

Then we save into the database and pass it as context to our templates:

```python
from django.shortcuts import  render
from meal_app.models import Meal
import requests

def get_meals(request):
    all_meals = {}
    if 'name' in request.GET:
        name = request.GET['name']
        url = 
        'https://www.themealdb.com/api/json/v1/1/search.php? 
        s=%s' % name
        response = requests.get(url)
        data = response.json()
        meals = data['meals']
       
        for i in meals:
            meal_data = Meal(
                name = i['strMeal'],
                category = i['strCategory'],
                instructions = i['strInstructions'],
                region = i['strArea'],
                slug = i['idMeal'],
                image_url = i['strMealThumb']
            )
            meal_data.save()
            all_meals = Meal.objects.all().order_by('-id')

    return render (request, 'meals/meal.html', { "all_meals": 
    all_meals} )

```

Within `meal,html`

```html
{% extends 'meals/base.html'%}
{% load static %}
{% block content %}
  <div class = "container">
    <div class = "text-center container">
      <br>
      <h2 class = "text-center">Search for your favorite Meals</h2> 
      <br>
      <form method="GET">
        <input type = "text" name = "name" placeholder="Search..." class = "text-center">
        <button type = "submit" class = "btn-danger btn-sm">SEARCH MEAL</button>
      </form> 
    </div> 
    <br><br>
    <div class="row">
      {% for meal in all_meals %}
        <div class="col-md-4 col-sm-6 col-lg-3">
          <div class="card">
            <img class="card-img-top" src="{{ meal.image_url }}" alt="Card image cap">
            <div class="card-body text-center">
              <p class="card-title">{{ meal.name }}</p>
              <hr>
              <p class="card-text">{{ meal.region }}</p>
              <a href="/meals/{{meal.id}}"
              ><input
                type="submit"
                value="Learn More"
                class="btn btn-danger btn-sm"
                type="button"
            /></a>
            </div>
          </div>
          <br><br><br>
        </div>
      {% endfor %}
    </div>
  </div>
{% endblock %}

```

Now if a user searches for a meal; it renders on the page and is automatically saved in the database.

`MEAL LIST PAGE`:


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/dxxesom9diwy36zz2nzr.png)



`DATABASE`:


![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/utdj8ijhvu0bupaww0x0.png)

lastly we create a Meal Detail page:


`meal_detail.html`

```html
{% extends 'meals/base.html'%}
{% load static %}
{% block content %}

<div class = "container"> 
    <br><br>
    <div class="row"> 
        <div class="col-md-5">
          <br>
          <img class="img-fluid" src="{{ meal.image_url }}" alt="" style = "width: 90%;">
          <br><br>
          <h3 class="card-title text-center ">{{ meal.name }}</h3>
        </div> 
        <div class="col-md-7 shadow-lg p-3 mb-5 bg-white rounded">
          <h1 class="my-3">Food Description</h1>
          <p class = "lead">{{ meal.instructions }}</p>
          <h1 class="my-3">Food Details</h1>
          <ul>
            <li>{{ meal.category }}</li>
            <li>{{ meal.region }}</li>
          </ul>
        </div>
    </div>
</div>

{% endblock %}
```

in `views.py`

```python
def meal_detail(request, id):
    meal = Meal.objects.get(id = id)
    print(meal)
    return render (
        request,
        'meals/meal_detail.html',
        {'meal': meal}
    )

```

Now when we click on the `Learn More` button we are taken to the `meal_details.html` template

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/45i7ivk2jykcuyb69j0l.png)

Thank you! ☺️