Initialize FishIQ development foundation
This commit is contained in:
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
class FishingConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "fishing"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)]
|
||||
operations = [
|
||||
migrations.CreateModel(name="Species", fields=[("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("common_name", models.CharField(max_length=120, unique=True)), ("scientific_name", models.CharField(blank=True, max_length=160))]),
|
||||
migrations.CreateModel(name="WaterBody", fields=[("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("name", models.CharField(max_length=180)), ("region", models.CharField(max_length=120)), ("latitude", models.DecimalField(decimal_places=6, max_digits=9)), ("longitude", models.DecimalField(decimal_places=6, max_digits=9)), ("species", models.ManyToManyField(blank=True, related_name="water_bodies", to="fishing.species"))], options={"constraints": [models.UniqueConstraint(fields=("name", "region"), name="unique_water_body_region")]}),
|
||||
migrations.CreateModel(name="Trip", fields=[("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("starts_at", models.DateTimeField()), ("ends_at", models.DateTimeField()), ("status", models.CharField(choices=[("planned", "Planned"), ("active", "Active"), ("complete", "Complete")], default="planned", max_length=12)), ("notes", models.TextField(blank=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ("owner", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name="trips", to=settings.AUTH_USER_MODEL)), ("target_species", models.ManyToManyField(related_name="trips", to="fishing.species")), ("water_body", models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name="trips", to="fishing.waterbody"))]),
|
||||
migrations.CreateModel(name="Recommendation", fields=[("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("title", models.CharField(max_length=180)), ("rationale", models.TextField()), ("tackle_setup", models.JSONField(default=dict)), ("confidence", models.DecimalField(decimal_places=3, max_digits=4)), ("generated_at", models.DateTimeField(auto_now_add=True)), ("trip", models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name="recommendations", to="fishing.trip"))]),
|
||||
]
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
|
||||
class Species(models.Model):
|
||||
common_name = models.CharField(max_length=120, unique=True)
|
||||
scientific_name = models.CharField(max_length=160, blank=True)
|
||||
|
||||
def __str__(self): return self.common_name
|
||||
|
||||
class WaterBody(models.Model):
|
||||
name = models.CharField(max_length=180)
|
||||
region = models.CharField(max_length=120)
|
||||
latitude = models.DecimalField(max_digits=9, decimal_places=6)
|
||||
longitude = models.DecimalField(max_digits=9, decimal_places=6)
|
||||
species = models.ManyToManyField(Species, related_name="water_bodies", blank=True)
|
||||
|
||||
class Meta:
|
||||
constraints = [models.UniqueConstraint(fields=["name", "region"], name="unique_water_body_region")]
|
||||
|
||||
def __str__(self): return f"{self.name}, {self.region}"
|
||||
|
||||
class Trip(models.Model):
|
||||
STATUS_CHOICES = [("planned", "Planned"), ("active", "Active"), ("complete", "Complete")]
|
||||
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="trips")
|
||||
water_body = models.ForeignKey(WaterBody, on_delete=models.PROTECT, related_name="trips")
|
||||
target_species = models.ManyToManyField(Species, related_name="trips")
|
||||
starts_at = models.DateTimeField()
|
||||
ends_at = models.DateTimeField()
|
||||
status = models.CharField(max_length=12, choices=STATUS_CHOICES, default="planned")
|
||||
notes = models.TextField(blank=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Recommendation(models.Model):
|
||||
trip = models.ForeignKey(Trip, on_delete=models.CASCADE, related_name="recommendations")
|
||||
title = models.CharField(max_length=180)
|
||||
rationale = models.TextField()
|
||||
tackle_setup = models.JSONField(default=dict)
|
||||
confidence = models.DecimalField(max_digits=4, decimal_places=3)
|
||||
generated_at = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
from rest_framework import serializers
|
||||
from .models import Recommendation, Species, Trip, WaterBody
|
||||
|
||||
class SpeciesSerializer(serializers.ModelSerializer):
|
||||
class Meta: model = Species; fields = "__all__"
|
||||
|
||||
class WaterBodySerializer(serializers.ModelSerializer):
|
||||
species = SpeciesSerializer(many=True, read_only=True)
|
||||
class Meta: model = WaterBody; fields = "__all__"
|
||||
|
||||
class TripSerializer(serializers.ModelSerializer):
|
||||
class Meta: model = Trip; fields = "__all__"; read_only_fields = ("owner",)
|
||||
|
||||
class RecommendationSerializer(serializers.ModelSerializer):
|
||||
class Meta: model = Recommendation; fields = "__all__"
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
from django.urls import include, path
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from .views import RecommendationViewSet, SpeciesViewSet, TripViewSet, WaterBodyViewSet, health
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register("species", SpeciesViewSet)
|
||||
router.register("water-bodies", WaterBodyViewSet)
|
||||
router.register("trips", TripViewSet, basename="trip")
|
||||
router.register("recommendations", RecommendationViewSet, basename="recommendation")
|
||||
urlpatterns = [path("health/", health), path("", include(router.urls))]
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
from django.http import JsonResponse
|
||||
from rest_framework import permissions, viewsets
|
||||
from .models import Recommendation, Species, Trip, WaterBody
|
||||
from .serializers import RecommendationSerializer, SpeciesSerializer, TripSerializer, WaterBodySerializer
|
||||
|
||||
def health(_request):
|
||||
return JsonResponse({"status": "ok", "service": "fishiq-api"})
|
||||
|
||||
class ReadOnlyCatalogViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
permission_classes = [permissions.AllowAny]
|
||||
|
||||
class SpeciesViewSet(ReadOnlyCatalogViewSet):
|
||||
queryset = Species.objects.all().order_by("common_name")
|
||||
serializer_class = SpeciesSerializer
|
||||
|
||||
class WaterBodyViewSet(ReadOnlyCatalogViewSet):
|
||||
queryset = WaterBody.objects.prefetch_related("species").all().order_by("name")
|
||||
serializer_class = WaterBodySerializer
|
||||
|
||||
class TripViewSet(viewsets.ModelViewSet):
|
||||
serializer_class = TripSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
def get_queryset(self): return Trip.objects.filter(owner=self.request.user).select_related("water_body")
|
||||
def perform_create(self, serializer): serializer.save(owner=self.request.user)
|
||||
|
||||
class RecommendationViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
serializer_class = RecommendationSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
def get_queryset(self): return Recommendation.objects.filter(trip__owner=self.request.user)
|
||||
|
||||
Reference in New Issue
Block a user