DEV Community

Cover image for How To Populate Your Database From An External API in Django.
Yahaya Kehinde
Yahaya Kehinde

Posted on • Edited on

How To Populate Your Database From An External API in Django.

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.

django-admin startproject meal_project
Enter fullscreen mode Exit fullscreen mode

Change into the project directory and create a new app:

cd meal_project
python manage.py startapp meal_app

Enter fullscreen mode Exit fullscreen mode

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

INSTALLED_APPS = [
'meal_app',
]
Enter fullscreen mode Exit fullscreen mode

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

TEMPLATES = [
 'DIRS': [os.path.join(BASE_DIR, 'templates')],
]
Enter fullscreen mode Exit fullscreen mode

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.

from django.contrib import admin
from django.urls import include, path
urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include ('meal_app.urls'))
]
Enter fullscreen mode Exit fullscreen mode

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

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")
]
Enter fullscreen mode Exit fullscreen mode

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

base.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>
Enter fullscreen mode Exit fullscreen mode

Then meal.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 %}

Enter fullscreen mode Exit fullscreen mode

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

Alt Text

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

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
Enter fullscreen mode Exit fullscreen mode

What our API looks like:

Alt Text

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

python manage.py makemigrations
python manage.py migrate
Enter fullscreen mode Exit fullscreen mode

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

pip install requests
Enter fullscreen mode Exit fullscreen mode

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

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} )

Enter fullscreen mode Exit fullscreen mode

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.

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']
Enter fullscreen mode Exit fullscreen mode

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.

 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']
            )

Enter fullscreen mode Exit fullscreen mode

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

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} )

Enter fullscreen mode Exit fullscreen mode

Within meal,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 %}

Enter fullscreen mode Exit fullscreen mode

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

DATABASE:

Alt Text

lastly we create a Meal Detail page:

meal_detail.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 %}
Enter fullscreen mode Exit fullscreen mode

in views.py

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

Enter fullscreen mode Exit fullscreen mode

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

Alt Text

Thank you! ☺️

Top comments (6)

Collapse
 
noorqureshi profile image
Noor Qureshi • Edited

This is perfect! However I do have one question! If i create one field through model and just put JSON ID through which i wanna fetch details how can i do that through admin dashboard instead of views?

Collapse
 
catbyteio profile image
catbyte-io

Did you mean from meal_app import views? If not, where did the product_app import come from?
Everything else is really easy to understand. Thank you!

Collapse
 
larrynoriega profile image
Larry Noriega

Mate, the whole article is something out of the box, pretty amazing out of common!

But... try to re think the whole "step by step" of the article because is not possible execute the migrate process before define the function meal_detail in views.py file and so on.

Anyway this article was completely helpful.

Collapse
 
madefoka profile image
Radek J. • Edited

Static files - do we have static files here?
We don't use static files in this project. You can remove all lines with load static.

Collapse
 
madefoka profile image
Radek J.

from product_app import views - this not gonna happen :)
Very nice tutorial. Thank you.

Collapse
 
windy_2212 profile image
Windy_2212

Well Explained ... Thank You ✌❀