Last updated: 21 August 2026
Nowadays, Django currency API integration has become common for modern applications. You can observe it especially in applications dealing with international financial data or e-commerce. Unlike a simple Python script, developers focus on performance, scalability, and architecture maintenance when implementing this integration.
In this tutorial, we explain Django currency API integration within an app. We will cover caching strategies, views, background updates using Celery, and API endpoints with Django REST framework. Let’s begin.
Prerequisites & Setup
- Python 3.x and Django installed in a virtual environment.
- Requests library: pip install requests
- Django REST Framework: pip install djangorestframework
- CurrencyFreaks API Key: Sign up to get your free API key. Still choosing a provider? Compare the 10 best currency exchange APIs first.
- Celery: pip install celery
- Redis client: pip install redis

Fetching Rates in a Django View
Model-view-template is essential when working with the Django currency API. We do not follow hardcoding approaches. Instead, we focus on creating a structured view. This view fetches the data and passes it to the frontend.
views.py
from django.shortcuts import render
def exchange_dashboard(request):
data = get_cached_rates() # defined in "Caching Strategy" section below
context = {
'rates': data.get('rates'),
'base': data.get('base'),
'date': data.get('date')
}
return render(request, 'exchange/dashboard.html', context)
Your template (exchange/dashboard.html) allows you to access and navigate a rates dictionary while dynamically displaying currency values with Django template tags.
Note: In the next section, we'll define the get_cached_rates() function.
urls.py
from django.urls import path
from .views import exchange_dashboard
urlpatterns = [
path('dashboard/', exchange_dashboard, name='exchange-dashboard'),
]
Exchange Rate API Django — Caching Strategy
Django workflow for an exchange rate API should not include hitting external APIs on every single page load; as rates typically update every hour, Django's built-in cache framework can reduce latency and save on API credits. The CurrencyFreaks free plan includes 1,000 API calls per month, so caching allows thousands of users to share a single hourly API request.
from django.core.cache import cache
from django.conf import settings
import requests
def get_cached_rates():
rates = cache.get('latest_currency_rates')
if not rates:
api_key = settings.CURRENCYFREAKS_API_KEY
try:
response = requests.get(
f"https://api.currencyfreaks.com/v2.0/rates/latest?apikey={api_key}",
timeout=5
)
rates = response.json()
cache.set('latest_currency_rates', rates, 3600)
except requests.exceptions.RequestException:
return {}
return rates
Utilizing the cache.get()/cache.set() pattern ensures your application remains responsive even during high traffic volumes.
Building a Currency Conversion Endpoint with Django REST Framework
If you are developing an independent frontend or mobile app, a Django REST Framework currency API endpoint can help expose conversion logic as a professional JSON API.
serializers.py
from rest_framework import serializers
class ConversionSerializer(serializers.Serializer):
from_currency = serializers.CharField(max_length=3)
to_currency = serializers.CharField(max_length=3)
amount = serializers.FloatField()
views.py (DRF)
from rest_framework.views import APIView
from rest_framework.response import Response
class ConvertCurrency(APIView):
def get(self, request):
serializer = ConversionSerializer(data=request.query_params)
if not serializer.is_valid():
return Response(serializer.errors, status=400)
rates = get_cached_rates()
from_currency = serializer.validated_data['from_currency']
to_currency = serializer.validated_data['to_currency']
amount = serializer.validated_data['amount']
rates_data = rates.get('rates', {})
from_rate = rates_data.get(from_currency)
to_rate = rates_data.get(to_currency)
if from_rate is None or to_rate is None:
return Response(
{'error': 'Invalid or unsupported currency code'},
status=400
)
from_rate = float(from_rate)
to_rate = float(to_rate)
# Note: Formula assumes USD is the base currency from the API provider.
converted_amount = (amount / from_rate) * to_rate
return Response({
'from': from_currency,
'to': to_currency,
'amount': amount,
'converted_amount': round(converted_amount, 2)
})
This approach ensures your currency conversion Django logic remains organized and usable across applications.
urls.py (DRF Endpoint)
from django.urls import path
from .views import ConvertCurrency
urlpatterns = [
path('api/convert/', ConvertCurrency.as_view(), name='currency-convert'),
]
Example API Request
GET /api/convert/?from_currency=USD&to_currency=EUR&amount=100
JSON Response:
{
"from": "USD",
"to": "EUR",
"amount": 100.0,
"converted_amount": 91.23
}
Scheduled Rate Updates with Celery
For an optimal Django Celery exchange rates implementation, it is ideal to fetch rates in the background so as to maintain "warm" cache conditions while never having to wait on 3rd-party API responses. This way, users never need to wait in their search for rates from third parties.
tasks.py
from celery import shared_task
import requests
from django.core.cache import cache
from django.conf import settings
@shared_task
def update_rates_task():
api_key = settings.CURRENCYFREAKS_API_KEY
response = requests.get(f"https://api.currencyfreaks.com/v2.0/rates/latest?apikey={api_key}")
if response.status_code == 200:
cache.set('latest_currency_rates', response.json(), 3600)
Celery Beat Configuration (settings.py)
CELERY_BEAT_SCHEDULE = {
'update-rates-every-hour': {
'task': 'exchange.tasks.update_rates_task',
'schedule': 3600.0,
},
}
Celery Beat configuration is placed in settings.py so Django can register scheduled tasks correctly in production setups.
Add your API key in settings.py using environment variables:
# settings.py
import os
CURRENCYFREAKS_API_KEY = os.getenv("CURRENCYFREAKS_API_KEY")
This avoids exposing sensitive credentials in source control.
Error Handling & Production Readiness
In real-life scenarios, APIs may fail, so your Django app must gracefully handle currency conversion requests when they do so.
import requests
import logging
from rest_framework.views import APIView
from rest_framework.response import Response
from django.core.cache import cache
from .serializers import ConversionSerializer
logger = logging.getLogger(__name__)
class SafeConvertCurrency(APIView):
def get(self, request):
serializer = ConversionSerializer(data=request.query_params)
if not serializer.is_valid():
return Response(serializer.errors, status=400)
try:
rates = get_cached_rates()
except requests.exceptions.RequestException as e:
logger.error(f"Currency API failed: {e}")
rates = cache.get('latest_currency_rates')
if not rates:
return Response(
{'error': 'Exchange rate service unavailable'},
status=503
)
from_currency = serializer.validated_data['from_currency']
to_currency = serializer.validated_data['to_currency']
amount = serializer.validated_data['amount']
rates_data = rates.get('rates', {})
from_rate = rates_data.get(from_currency)
to_rate = rates_data.get(to_currency)
if from_rate is None or to_rate is None:
return Response(
{'error': 'Invalid or unsupported currency code'},
status=400
)
from_rate = float(from_rate)
to_rate = float(to_rate)
# Note: Formula assumes USD is the base currency from the API provider.
converted_amount = (amount / from_rate) * to_rate
return Response({
'from': from_currency,
'to': to_currency,
'amount': amount,
'converted_amount': round(converted_amount, 2)
})
By combining DRF as the interface, the Django Cache for performance, and Celery for background processing, you create a robust system capable of handling exchange rates with professionalism.
Conclusion
By aligning currency integration with Django's architecture, including views, caching, API endpoints, and background workers, you can avoid unnecessary API calls while increasing performance.
Django Cache reduces latency, Django REST Framework provides clean APIs, and Celery keeps exchange rates updated without blocking user requests, all making for an approach that is production-ready and scalable for applications handling real-time financial data.
FAQs
How Should I Handle Currency Conversion in Django Templates?
For best results, currency conversion should be handled using an exchange rate view context with either custom template filters or multiplication; for optimal UI, use a Django REST Framework endpoint that handles calculations via JavaScript instead. This ensures updated pricing doesn't necessitate full page reloads to display accurately.
Where Is the Best Place to Store Exchange Rates in Django?
For high-performance applications, temporary storage (e.g., 1 hour) should be handled using Redis or Memcached Cache; for historical reports or audit trails, however, rates should be stored in your primary database using an ExchangeRate model that updates regularly via Celery tasks.
Why Should I Use Celery for Currency Updates Instead of Updating on Page Load?
Updating on page load forces users to wait for third-party API responses, adding significant latency and risking a 504 Gateway Timeout if an API goes down. Django Celery exchange rates management allows you to fetch data in the background so your users always see a "warm" cache with no wait time for updates.
How Do I Handle API Rate Limits in a Django Project?
One effective strategy to remain within CurrencyFreaks plan limits is by employing a cache.get()/cache.set() cycle, checking cache first before only hitting the API when data has expired. This allows for thousands of users to be served using one API call per hour!
Is It Better to Use a Decimal or Float Field for Currency in Django Models?
Always use DecimalField when storing currency values in your models, since floats can lead to rounding errors that cause lost pennies. Also, ensure your currency conversion Django logic converts API responses into Decimals before performing calculations to maintain financial accuracy.
Sign Up for free at CurrencyFreaks and get your business's most accurate exchange rates.
