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