Build an Astrology Web App with Django & Vedika API

Build an Astrology Web App with Django and Vedika API
Published: March 13, 2026 | By Vedika Intelligence | Reading time: 14 minutes

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

Step 1: Project Setup

# Create and activate virtual environment python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate # Install dependencies pip install django djangorestframework requests django-redis python-decouple # Create Django project and astrology app django-admin startproject astrology_site . python manage.py startapp astrology

settings.py — Configure Caching and Environment

# astrology_site/settings.py 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 configuration VEDIKA_API_KEY = config('VEDIKA_API_KEY') VEDIKA_BASE_URL = 'https://api.vedika.io' # Redis cache — birth chart data is deterministic, cache aggressively 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 # 30 days (deterministic) CACHE_DAILY_HOROSCOPE_SECONDS = 86400 # 24 hours CACHE_AI_QUERY_SECONDS = 3600 # 1 hour per question

Step 2: Define Models

Store user birth profiles so they don't need to re-enter data on every visit:

# astrology/models.py 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'
# Run migrations 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:

# astrology/vedika_service.py 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

# astrology/views.py 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

# astrology/urls.py 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'), ]
# astrology_site/urls.py 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:

# astrology/serializers.py 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')
# astrology/api_views.py 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:

<!-- templates/astrology/birth_chart.html --> {% 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

# .env (never commit this file) 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)

# astrology/tasks.py — async pre-fetching with Celery 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 # Call after user submits birth details: # prefetch_birth_chart.delay(request.user.id)

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:

Next steps:

  1. Get your Vedika API key at vedika.io/signup
  2. Run pip install django djangorestframework requests django-redis
  3. Create a .env file with your API key and Redis URL
  4. Copy the service layer and views above into your project
  5. 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.

Try the #1 Vedic Astrology API

140+ endpoints, 30 languages, Swiss Ephemeris precision. Free sandbox included — no credit card required.

Get Free API Key