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
Change into the project directory and create a new app:
cd meal_project
python manage.py startapp meal_app
Add the newly created app into installed apps under 'settings.py'
INSTALLED_APPS = [
'meal_app',
]
In the root directory, create a 'templates' folder and add it within 'settings.py'
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.
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.
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
:
{% 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
{% 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.
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
What our API looks like:
It's now time to migrate our database and create our database tables.
python manage.py makemigrations
python manage.py migrate
Next, we need to install a python library that helps in making HTTP requests;
pip install requests
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} )
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']
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']
)
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} )
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 %}
Now if a user searches for a meal; it renders on the page and is automatically saved in the database.
MEAL LIST PAGE
:
DATABASE
:
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 %}
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}
)
Now when we click on the Learn More
button we are taken to the meal_details.html
template
Thank you! βΊοΈ
Top comments (6)
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?
Did you mean
from meal_app import views
? If not, where did theproduct_app
import come from?Everything else is really easy to understand. Thank you!
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.
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.
from product_app import views - this not gonna happen :)
Very nice tutorial. Thank you.
Well Explained ... Thank You ββ€