feat: Feed map with real data
This commit is contained in:
33
src/fellchensammlung/api/renderers.py
Normal file
33
src/fellchensammlung/api/renderers.py
Normal file
@@ -0,0 +1,33 @@
|
||||
from rest_framework.renderers import BaseRenderer
|
||||
import json
|
||||
|
||||
|
||||
class GeoJSONRenderer(BaseRenderer):
|
||||
media_type = 'application/json'
|
||||
format = 'geojson'
|
||||
charset = 'utf-8'
|
||||
|
||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||
features = []
|
||||
for item in data:
|
||||
coords = item["coordinates"]
|
||||
if coords:
|
||||
feature = {
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Point",
|
||||
"coordinates": coords
|
||||
},
|
||||
"properties": {
|
||||
k: v for k, v in item.items()
|
||||
},
|
||||
"id": f"adoptionnotice/{item['id']}"
|
||||
}
|
||||
features.append(feature)
|
||||
|
||||
geojson = {
|
||||
"type": "FeatureCollection",
|
||||
"generator": "notfellchen",
|
||||
"features": features
|
||||
}
|
||||
return json.dumps(geojson)
|
@@ -1,6 +1,6 @@
|
||||
from ..models import Animal, RescueOrganization, AdoptionNotice, Species, Image, Location
|
||||
from rest_framework import serializers
|
||||
|
||||
import math
|
||||
|
||||
class AdoptionNoticeSerializer(serializers.HyperlinkedModelSerializer):
|
||||
location = serializers.PrimaryKeyRelatedField(
|
||||
@@ -32,6 +32,42 @@ class AdoptionNoticeSerializer(serializers.HyperlinkedModelSerializer):
|
||||
"group_only", "location", "location_details", "organization", "photos"]
|
||||
|
||||
|
||||
class AdoptionNoticeGeoJSONSerializer(serializers.ModelSerializer):
|
||||
species = serializers.SerializerMethodField()
|
||||
title = serializers.CharField(source='name')
|
||||
url = serializers.SerializerMethodField()
|
||||
location_hr = serializers.SerializerMethodField()
|
||||
coordinates = serializers.SerializerMethodField()
|
||||
|
||||
class Meta:
|
||||
model = AdoptionNotice
|
||||
fields = ('id', 'species', 'title', 'description', 'url', 'location_hr', 'coordinates')
|
||||
|
||||
def get_species(self, obj):
|
||||
return None
|
||||
|
||||
def get_url(self, obj):
|
||||
return obj.get_absolute_url()
|
||||
|
||||
def get_coordinates(self, obj):
|
||||
"""
|
||||
Coordinates are randomly moved around real location, roughly in a circle. The object id is used as angle so that
|
||||
points are always displayed at the same location (as if they were a seed for a random function).
|
||||
|
||||
It's not exactly a circle, because the earth is round.
|
||||
"""
|
||||
if obj.location:
|
||||
longitude_addition = math.sin(obj.id)/2000
|
||||
latitude_addition = math.cos(obj.id)/2000
|
||||
return [obj.location.longitude+longitude_addition, obj.location.latitude+latitude_addition]
|
||||
return None
|
||||
|
||||
def get_location_hr(self, obj):
|
||||
if obj.location:
|
||||
return f"{obj.location.city}"
|
||||
return None
|
||||
|
||||
|
||||
class AnimalCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Animal
|
||||
|
@@ -1,11 +1,13 @@
|
||||
from django.urls import path
|
||||
from .views import (
|
||||
AdoptionNoticeApiView,
|
||||
AnimalApiView, RescueOrganizationApiView, AddImageApiView, SpeciesApiView, LocationApiView
|
||||
AnimalApiView, RescueOrganizationApiView, AddImageApiView, SpeciesApiView, LocationApiView,
|
||||
AdoptionNoticeGeoJSONView
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
path("adoption_notice", AdoptionNoticeApiView.as_view(), name="api-adoption-notice-list"),
|
||||
path("adoption_notice.geojson", AdoptionNoticeGeoJSONView.as_view(), name="api-adoption-notice-list-geojson"),
|
||||
path("adoption_notice/<int:id>/", AdoptionNoticeApiView.as_view(), name="api-adoption-notice-detail"),
|
||||
path("animals/", AnimalApiView.as_view(), name="api-animal-list"),
|
||||
path("animals/<int:id>/", AnimalApiView.as_view(), name="api-animal-detail"),
|
||||
|
@@ -1,13 +1,16 @@
|
||||
from django.db.models import Q
|
||||
from rest_framework.generics import ListAPIView
|
||||
|
||||
from fellchensammlung.api.serializers import LocationSerializer
|
||||
from fellchensammlung.api.serializers import LocationSerializer, AdoptionNoticeGeoJSONSerializer
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework.response import Response
|
||||
from django.db import transaction
|
||||
from fellchensammlung.models import AdoptionNotice, Animal, Log, TrustLevel, Location
|
||||
from fellchensammlung.models import AdoptionNotice, Animal, Log, TrustLevel, Location, AdoptionNoticeStatus
|
||||
from fellchensammlung.tasks import post_adoption_notice_save, post_rescue_org_save
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from .renderers import GeoJSONRenderer
|
||||
from .serializers import (
|
||||
AnimalGetSerializer,
|
||||
AnimalCreateSerializer,
|
||||
@@ -354,3 +357,10 @@ class LocationApiView(APIView):
|
||||
{"message": "Location created successfully!", "id": location.pk},
|
||||
status=status.HTTP_201_CREATED,
|
||||
)
|
||||
|
||||
|
||||
class AdoptionNoticeGeoJSONView(ListAPIView):
|
||||
queryset = AdoptionNotice.objects.select_related('location').filter(location__isnull=False).filter(
|
||||
adoptionnoticestatus__major_status=AdoptionNoticeStatus.ACTIVE)
|
||||
serializer_class = AdoptionNoticeGeoJSONSerializer
|
||||
renderer_classes = [GeoJSONRenderer]
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{% load custom_tags %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% get_current_language as LANGUAGE_CODE%}
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ LANGUAGE_CODE }}">
|
||||
<head>
|
||||
|
@@ -63,7 +63,7 @@
|
||||
// Load adoption notices as geojson
|
||||
map.addSource('adoption-notices', {
|
||||
type: 'geojson',
|
||||
data: '{% static "fellchensammlung/ans.geojson" %}',
|
||||
data: '{% url "api-adoption-notice-list-geojson" %}',
|
||||
cluster: true,
|
||||
clusterMaxZoom: 14,
|
||||
clusterRadius: 50
|
||||
@@ -121,6 +121,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// inspect a cluster on click
|
||||
map.on('click', 'clusters', async (e) => {
|
||||
const features = map.queryRenderedFeatures(e.point, {
|
||||
|
Reference in New Issue
Block a user