PICK SKY overlay: D3 natal wheel, Character model, PySwiss aspects+tz
PySwiss: - calculate_aspects() in calc.py (conjunction/sextile/square/trine/opposition with orbs) - /api/tz/ endpoint (timezonefinder lat/lon → IANA timezone) - aspects included in /api/chart/ response - timezonefinder==8.2.2 added to requirements - 14 new unit tests (test_calc.py) + 12 new integration tests (TimezoneApiTest, aspect fields) Main app: - Sign, Planet, AspectType, HouseLabel reference models + seeded migrations (0032–0033) - Character model with birth_dt/lat/lon/place, house_system, chart_data, celtic_cross, confirmed_at/retired_at lifecycle (migration 0034) - natus_preview proxy view: calls PySwiss /api/chart/ + optional /api/tz/ auto-resolution, computes planet-in-house distinctions, returns enriched JSON - natus_save view: find-or-create draft Character, confirmed_at on action='confirm' - natus-wheel.js: D3 v7 SVG natal wheel (elements pie, signs, houses, planets, aspects, ASC/MC axes); NatusWheel.draw() / redraw() / clear() - _natus_overlay.html: Nominatim place autocomplete (debounced 400ms), geolocation button with reverse-geocode city name, live chart preview (debounced 300ms), tz auto-fill, NVM / SAVE SKY footer; html.natus-open class toggle pattern - _natus.scss: Gaussian backdrop+modal, two-column form|wheel layout, suggestion dropdown, portrait collapse at 600px, landscape sidebar z-index sink - room.html: include overlay when table_status == SKY_SELECT Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from timezonefinder import TimezoneFinder
|
||||
|
||||
import swisseph as swe
|
||||
|
||||
from .calc import (
|
||||
DEFAULT_HOUSE_SYSTEM,
|
||||
calculate_aspects,
|
||||
get_element_counts,
|
||||
get_julian_day,
|
||||
get_planet_positions,
|
||||
@@ -61,10 +63,41 @@ def chart(request):
|
||||
'planets': planets,
|
||||
'houses': houses,
|
||||
'elements': get_element_counts(planets),
|
||||
'aspects': calculate_aspects(planets),
|
||||
'house_system': house_system,
|
||||
})
|
||||
|
||||
|
||||
_tf = TimezoneFinder()
|
||||
|
||||
|
||||
def timezone_lookup(request):
|
||||
"""GET /api/tz/ — resolve IANA timezone string from lat/lon.
|
||||
|
||||
Query params: lat (float), lon (float)
|
||||
Returns: { "timezone": "America/New_York" }
|
||||
Returns 404 JSON { "timezone": null } if coordinates fall in international
|
||||
waters (no timezone found) — not an error, just no result.
|
||||
"""
|
||||
lat_str = request.GET.get('lat')
|
||||
lon_str = request.GET.get('lon')
|
||||
|
||||
if lat_str is None or lon_str is None:
|
||||
return HttpResponse(status=400)
|
||||
|
||||
try:
|
||||
lat = float(lat_str)
|
||||
lon = float(lon_str)
|
||||
except ValueError:
|
||||
return HttpResponse(status=400)
|
||||
|
||||
if not (-90 <= lat <= 90) or not (-180 <= lon <= 180):
|
||||
return HttpResponse(status=400)
|
||||
|
||||
tz = _tf.timezone_at(lat=lat, lng=lon)
|
||||
return JsonResponse({'timezone': tz})
|
||||
|
||||
|
||||
def charts_list(request):
|
||||
date_from_str = request.GET.get('date_from')
|
||||
date_to_str = request.GET.get('date_to')
|
||||
|
||||
Reference in New Issue
Block a user