Django is the fastest path from idea to production astrology SaaS. With its batteries-included philosophy — ORM, admin panel, auth system, template engine, and REST Framework — you get everything needed to build a subscription astrology platform without assembling framework components from scratch.
In this tutorial we'll build a complete Django astrology web app backed by Vedika API — the only B2B astrology API with an AI-powered natural language engine, 140+ calculation endpoints, and Swiss Ephemeris precision. You'll ship working birth chart pages, a daily horoscope view, a DRF API endpoint, and Redis caching that cuts API costs by up to 80%.
What You'll Build: A Django astrology web app with user birth profiles (models), birth chart and horoscope views, Jinja/Django templates for display, a Django REST Framework API endpoint for mobile app consumption, and Redis caching so repeated queries don't hit Vedika API unnecessarily.
Why Django for Astrology Apps?
ORM for Birth Profiles
Store user birth data, saved charts, and subscription status in Django models with zero SQL writing. Migrations handle schema changes safely.
Built-In Admin
Manage users, birth profiles, and subscription tiers from Django admin. No custom dashboard needed for internal operations.
DRF for Mobile APIs
Expose your astrology data to React Native or Flutter apps through Django REST Framework — typed serializers, auth, and pagination included.
Python Ecosystem
Access the full Python data science stack for additional processing: pandas for chart analytics, matplotlib for visualizations, celery for async tasks.
Prerequisites
- Python 3.11 or later
- pip and virtualenv (or pipenv/poetry)
- Redis (local or cloud) for caching
- Vedika API key — get yours here
- Basic Django knowledge (models, views, URLs)
Step 1: Project Setup
python -m venv venv
source venv/bin/activate
pip install django djangorestframework requests django-redis python-decouple
django-admin startproject astrology_site .
python manage.py startapp astrology
settings.py — Configure Caching and Environment
from decouple import config
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework',
'astrology',
]
VEDIKA_API_KEY = config('VEDIKA_API_KEY')
VEDIKA_BASE_URL = 'https://api.vedika.io'
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': config('REDIS_URL', default='redis://127.0.0.1:6379/1'),
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
},
'KEY_PREFIX': 'vedika',
}
}
CACHE_BIRTH_CHART_SECONDS = 86400 * 30
CACHE_DAILY_HOROSCOPE_SECONDS = 86400
CACHE_AI_QUERY_SECONDS = 3600
Step 2: Define Models
Store user birth profiles so they don't need to re-enter data on every visit:
from django.db import models
from django.contrib.auth.models import User
class BirthProfile(models.Model):
"""Stores a user's birth details for astrology calculations."""
user = models.OneToOneField(
User, on_delete=models.CASCADE, related_name='birth_profile'
)
birth_datetime = models.DateTimeField(
help_text='Local birth date and time'
)
latitude = models.DecimalField(
max_digits=9, decimal_places=6,
help_text='Birth place latitude in decimal degrees'
)
longitude = models.DecimalField(
max_digits=9, decimal_places=6,
help_text='Birth place longitude in decimal degrees'
)
timezone_offset = models.CharField(
max_length=6, default='+05:30',
help_text='UTC offset, e.g. +05:30 for IST'
)
birth_city = models.CharField(max_length=100, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def to_vedika_datetime(self):
"""Format birth datetime for Vedika API."""
dt = self.birth_datetime
return f"{dt.strftime('%Y-%m-%dT%H:%M:%S')}{self.timezone_offset}"
def __str__(self):
return f"{self.user.username} born {self.birth_datetime.date()}"
class Meta:
verbose_name = 'Birth Profile'
python manage.py makemigrations astrology
python manage.py migrate
Step 3: Build the Vedika API Service Layer
Keep all Vedika API calls in a dedicated service module. This separates HTTP concerns from view logic and makes testing straightforward:
import hashlib
import requests
from django.conf import settings
from django.core.cache import cache
def _headers():
return {
'Authorization': f'Bearer {settings.VEDIKA_API_KEY}',
'Content-Type': 'application/json',
}
def _cache_key(*args):
"""Generate a short deterministic cache key from arguments."""
raw = ':'.join(str(a) for a in args)
return hashlib.sha256(raw.encode()).hexdigest()[:32]
def get_birth_chart(datetime_str, latitude, longitude, timezone='+05:30'):
"""
Fetch a Vedic birth chart from Vedika API.
Results are cached for 30 days — birth charts are deterministic.
"""
cache_key = f'chart:{_cache_key(datetime_str, latitude, longitude)}'
cached = cache.get(cache_key)
if cached:
return cached
payload = {
'datetime': datetime_str,
'latitude': float(latitude),
'longitude': float(longitude),
'timezone': timezone,
}
response = requests.post(
f'{settings.VEDIKA_BASE_URL}/v2/astrology/birth-chart',
json=payload,
headers=_headers(),
timeout=30,
)
response.raise_for_status()
data = response.json()
cache.set(cache_key, data, settings.CACHE_BIRTH_CHART_SECONDS)
return data
def get_daily_horoscope(zodiac_sign):
"""
Fetch daily horoscope for a zodiac sign.
Cached for 24 hours — same sign gets same prediction all day.
"""
from datetime import date
today = date.today().isoformat()
cache_key = f'horoscope:{zodiac_sign}:{today}'
cached = cache.get(cache_key)
if cached:
return cached
response = requests.get(
f'{settings.VEDIKA_BASE_URL}/v2/western/horoscope/{zodiac_sign.lower()}',
headers=_headers(),
timeout=15,
)
response.raise_for_status()
data = response.json()
cache.set(cache_key, data, settings.CACHE_DAILY_HOROSCOPE_SECONDS)
return data
def query_ai(question, datetime_str, latitude, longitude, timezone='+05:30', language='en'):
"""
Send a natural language astrology question to Vedika AI.
Cached for 1 hour per unique question+birth data combination.
"""
cache_key = f'ai:{_cache_key(question, datetime_str, latitude, longitude, language)}'
cached = cache.get(cache_key)
if cached:
return cached
payload = {
'question': question,
'birthDetails': {
'datetime': datetime_str,
'latitude': float(latitude),
'longitude': float(longitude),
'timezone': timezone,
},
'language': language,
}
response = requests.post(
f'{settings.VEDIKA_BASE_URL}/api/v1/astrology/query',
json=payload,
headers=_headers(),
timeout=45,
)
response.raise_for_status()
data = response.json()
cache.set(cache_key, data, settings.CACHE_AI_QUERY_SECONDS)
return data
Step 4: Build Django Views
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.views.decorators.http import require_POST
from django.contrib import messages
from . import vedika_service
from .models import BirthProfile
@login_required
def birth_chart_view(request):
"""Display the user's Vedic birth chart."""
try:
profile = request.user.birth_profile
except BirthProfile.DoesNotExist:
messages.info(request, 'Please enter your birth details first.')
return redirect('astrology:setup')
chart_data = None
error = None
try:
chart_data = vedika_service.get_birth_chart(
datetime_str=profile.to_vedika_datetime(),
latitude=profile.latitude,
longitude=profile.longitude,
timezone=profile.timezone_offset,
)
except Exception as e:
error = str(e)
return render(request, 'astrology/birth_chart.html', {
'chart': chart_data,
'profile': profile,
'error': error,
})
def daily_horoscope_view(request):
"""Show daily horoscope for a selected zodiac sign."""
sign = request.GET.get('sign', 'aries')
horoscope = None
error = None
ZODIAC_SIGNS = [
'aries', 'taurus', 'gemini', 'cancer',
'leo', 'virgo', 'libra', 'scorpio',
'sagittarius', 'capricorn', 'aquarius', 'pisces',
]
if sign.lower() not in ZODIAC_SIGNS:
sign = 'aries'
try:
horoscope = vedika_service.get_daily_horoscope(sign)
except Exception as e:
error = str(e)
return render(request, 'astrology/daily_horoscope.html', {
'horoscope': horoscope,
'selected_sign': sign,
'zodiac_signs': ZODIAC_SIGNS,
'error': error,
})
@login_required
@require_POST
def ai_chat_view(request):
"""Handle AI astrology question submission."""
question = request.POST.get('question', '').strip()
if not question:
return render(request, 'astrology/ai_chat.html', {'error': 'Please enter a question.'})
try:
profile = request.user.birth_profile
except BirthProfile.DoesNotExist:
return redirect('astrology:setup')
answer = None
error = None
try:
result = vedika_service.query_ai(
question=question,
datetime_str=profile.to_vedika_datetime(),
latitude=profile.latitude,
longitude=profile.longitude,
timezone=profile.timezone_offset,
)
answer = result.get('answer')
except Exception as e:
error = str(e)
return render(request, 'astrology/ai_chat.html', {
'question': question,
'answer': answer,
'error': error,
})
Step 5: URL Configuration
from django.urls import path
from . import views
app_name = 'astrology'
urlpatterns = [
path('', views.daily_horoscope_view, name='home'),
path('birth-chart/', views.birth_chart_view, name='birth_chart'),
path('ask/', views.ai_chat_view, name='ai_chat'),
path('horoscope/', views.daily_horoscope_view, name='horoscope'),
]
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('astrology.urls', namespace='astrology')),
]
Step 6: Django REST Framework API Endpoint
Build a DRF endpoint so your mobile app or JavaScript frontend can call your Django backend instead of Vedika directly — keeping your API key server-side:
from rest_framework import serializers
class BirthChartRequestSerializer(serializers.Serializer):
datetime = serializers.CharField(
max_length=30,
help_text='ISO 8601 datetime with UTC offset: 1990-06-15T14:30:00+05:30'
)
latitude = serializers.FloatField(min_value=-90, max_value=90)
longitude = serializers.FloatField(min_value=-180, max_value=180)
timezone = serializers.CharField(max_length=6, default='+05:30')
class AIQuerySerializer(serializers.Serializer):
question = serializers.CharField(max_length=500)
datetime = serializers.CharField(max_length=30)
latitude = serializers.FloatField(min_value=-90, max_value=90)
longitude = serializers.FloatField(min_value=-180, max_value=180)
timezone = serializers.CharField(max_length=6, default='+05:30')
language = serializers.CharField(max_length=5, default='en')
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from .serializers import BirthChartRequestSerializer, AIQuerySerializer
from . import vedika_service
class BirthChartAPIView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
serializer = BirthChartRequestSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
d = serializer.validated_data
try:
chart = vedika_service.get_birth_chart(
datetime_str=d['datetime'],
latitude=d['latitude'],
longitude=d['longitude'],
timezone=d['timezone'],
)
return Response(chart)
except Exception as e:
return Response(
{'error': str(e)},
status=status.HTTP_502_BAD_GATEWAY
)
class AIQueryAPIView(APIView):
permission_classes = [IsAuthenticated]
def post(self, request):
serializer = AIQuerySerializer(data=request.data)
serializer.is_valid(raise_exception=True)
d = serializer.validated_data
try:
result = vedika_service.query_ai(
question=d['question'],
datetime_str=d['datetime'],
latitude=d['latitude'],
longitude=d['longitude'],
timezone=d['timezone'],
language=d['language'],
)
return Response(result)
except Exception as e:
return Response(
{'error': str(e)},
status=status.HTTP_502_BAD_GATEWAY
)
Step 7: Django Template
Create templates/astrology/birth_chart.html to display the chart data:
{% extends "base.html" %}
{% block content %}
<div class="chart-container">
<h1>Your Vedic Birth Chart</h1>
{% if error %}
<div class="alert alert-danger">{{ error }}</div>
{% elif chart %}
<div class="chart-summary">
<p><strong>Ascendant (Lagna):</strong> {{ chart.ascendant }}</p>
<p><strong>Moon Sign (Rashi):</strong> {{ chart.moonSign }}</p>
<p><strong>Sun Sign:</strong> {{ chart.sunSign }}</p>
</div>
<h2>Planetary Positions</h2>
<table class="planets-table">
<thead>
<tr>
<th>Planet</th><th>Sign</th><th>House</th>
<th>Degree</th><th>Dignity</th><th>Status</th>
</tr>
</thead>
<tbody>
{% for planet in chart.planets %}
<tr>
<td>{{ planet.name }}</td>
<td>{{ planet.sign }}</td>
<td>{{ planet.house }}</td>
<td>{{ planet.degree|floatformat:2 }}°</td>
<td>{{ planet.dignity }}</td>
<td>{% if planet.retrograde %}Retrograde{% else %}Direct{% endif %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if chart.activeYogas %}
<h2>Active Yogas</h2>
<ul>
{% for yoga in chart.activeYogas %}
<li>{{ yoga }}</li>
{% endfor %}
</ul>
{% endif %}
<h2>Current Dasha</h2>
<p>
<strong>{{ chart.currentDasha.mahadasha }}</strong> /
{{ chart.currentDasha.antardasha }}
<em>(ends {{ chart.currentDasha.endsAt }})</em>
</p>
<div class="ask-section">
<h2>Ask About Your Chart</h2>
<form method="post" action="{% url 'astrology:ai_chat' %}">
{% csrf_token %}
<input type="text" name="question"
placeholder="What does my 10th house say about career?"
class="question-input">
<button type="submit" class="btn-primary">Ask Vedika AI</button>
</form>
</div>
{% endif %}
</div>
{% endblock %}
Production Best Practices
Environment Variables
VEDIKA_API_KEY=vk_live_your_key_here
REDIS_URL=redis://127.0.0.1:6379/1
SECRET_KEY=your-django-secret-key
DEBUG=False
ALLOWED_HOSTS=yourdomain.com
Timeout and Error Handling
Always set a timeout parameter on requests.post() calls. The AI endpoint can take up to 30 seconds — without a timeout, a slow response will hang your Django worker process. Use Django's messages framework to surface user-friendly errors instead of 500 pages.
Async with Celery (Optional)
from celery import shared_task
from . import vedika_service
from .models import BirthProfile
@shared_task
def prefetch_birth_chart(user_id):
"""Pre-warm the Redis cache for a user's birth chart after signup."""
try:
profile = BirthProfile.objects.get(user_id=user_id)
vedika_service.get_birth_chart(
datetime_str=profile.to_vedika_datetime(),
latitude=profile.latitude,
longitude=profile.longitude,
timezone=profile.timezone_offset,
)
except BirthProfile.DoesNotExist:
pass
Why Vedika API for Django Projects?
140+ Endpoints
Birth charts, dashas, yogas, panchang, numerology, compatibility, transits — call them all from Python's requests library.
AI Natural Language
One endpoint replaces 140 separate calculation calls for user-facing features. Users ask questions, Vedika answers.
Swiss Ephemeris Precision
Astronomical-grade planetary positions. Matches professional desktop astrology software. No accuracy compromises.
30 Languages
Hindi, Tamil, Telugu, Bengali — 30 languages supported natively. Build for India's linguistic diversity from a single API.
Deterministic Caching
Birth chart results for the same datetime and location never change. Cache indefinitely in Redis to minimize API costs dramatically.
Starts at $12/month
Starter plan covers most Django hobby or early-stage projects. Wallet-based credits scale with your usage transparently.
Conclusion
Django and Vedika API are a natural pair for building astrology web products. The combination gives you:
- Rapid development: ORM, auth, admin, and templates eliminate boilerplate so you focus on astrology features
- Cost control: Redis caching on deterministic chart data cuts API usage by 70-80% in production
- Mobile-ready: DRF endpoints serve your Flutter or React Native apps with typed, authenticated responses
- AI built-in: Natural language queries let users ask anything without you implementing astrology logic
- Production-grade: Celery for async pre-fetching, environment variables for secrets, error boundaries in views
Next steps:
- Get your Vedika API key at vedika.io/signup
- Run
pip install django djangorestframework requests django-redis
- Create a
.env file with your API key and Redis URL
- Copy the service layer and views above into your project
- Add Celery for pre-warming caches after user signup
For complete endpoint documentation, request/response schemas, and sandbox testing, visit our developer documentation or view pricing.
About Vedika Intelligence: Vedika is the only B2B astrology API with an AI-powered chatbot and 140+ calculation endpoints, serving production apps worldwide. Built on Swiss Ephemeris for astronomical precision, supporting Vedic, Western, and KP astrology across 30 languages. The world's first astrology MCP server.