from tastypie import fields from tastypie.authentication import SessionAuthentication from tastypie.resources import ModelResource from django.contrib.gis import geos from django.urls import reverse from .models import Lieu, Normalien, Stage from .utils import approximate_distance class EnScolariteAuthentication(SessionAuthentication): def is_authenticated(self, request, **kwargs): if super().is_authenticated(request, **kwargs): return request.user.profil.en_scolarite return False # API principale pour les lieux class LieuResource(ModelResource): # stages = fields.ToManyField("avisstage.api.StageResource", # "stages", use_in="detail", full=True) class Meta: queryset = Lieu.objects.all() resource_name = "lieu" fields = ["nom", "ville", "pays", "coord", "type_lieu", "id"] # login_required authentication = SessionAuthentication() # Filtres personnalisés def build_filters(self, filters=None, **kwargs): if filters is None: filters = {} orm_filters = super(LieuResource, self).build_filters(filters, **kwargs) # Trouver les lieux à proximités d'un point donné if "lng" in filters and "lat" in filters: lat = float(filters["lat"]) lng = float(filters["lng"]) pt = geos.Point((lng, lat), srid=4326) self.reference_point = pt orm_filters["coord__distance_lte"] = (pt, 10000) # Filtrer les lieux qui ont déjà des stages if "has_stage" in filters: orm_filters["stages__public"] = True return orm_filters # Custom apply filters pour ajouter le "distinct" def apply_filters(self, request, applicable_filters): return self.get_object_list(request).filter(**applicable_filters).distinct() # Ajout d'informations def dehydrate(self, bundle): bundle = super(LieuResource, self).dehydrate(bundle) obj = bundle.obj bundle.data["coord"] = {"lat": float(obj.coord.y), "lng": float(obj.coord.x)} # Distance au point recherché if "lat" in bundle.request.GET and "lng" in bundle.request.GET: bundle.data["distance"] = approximate_distance( self.reference_point, bundle.obj.coord ) # Autres infos utiles bundle.data["pays_nom"] = obj.get_pays_display() bundle.data["type_lieu_nom"] = obj.type_lieu_fancy # TODO use annotate? bundle.data["num_stages"] = obj.stages.filter(public=True).count() return bundle # API sur un stage class StageResource(ModelResource): class Meta: queryset = Stage.objects.filter(public=True) resource_name = "stage" fields = ["sujet", "date_debut", "date_fin", "matieres", "id"] # login_required authentication = EnScolariteAuthentication() # Filtres personnalisés def build_filters(self, filters=None, **kwargs): if filters is None: filters = {} orm_filters = super(StageResource, self).build_filters(filters, **kwargs) # Récupération des stages à un lieu donné if "lieux" in filters: flieux = map(int, filters["lieux"].split(",")) orm_filters["lieux__id__in"] = flieux return orm_filters # Informations à ajouter def dehydrate(self, bundle): bundle = super(StageResource, self).dehydrate(bundle) obj = bundle.obj # Affichage des manytomany en condensé bundle.data["auteur"] = obj.auteur.nom bundle.data["thematiques"] = list( obj.thematiques.all().values_list("name", flat=True) ) bundle.data["matieres"] = list(obj.matieres.all().values_list("nom", flat=True)) # Adresse de la fiche de stage bundle.data["url"] = reverse("avisstage:stage", kwargs={"pk": obj.id}) return bundle # Auteurs des fiches (TODO supprimer ?) class AuteurResource(ModelResource): stages = fields.ToManyField( "avisstage.api.StageResource", "stages", use_in="detail" ) class Meta: queryset = Normalien.objects.all() resource_name = "profil" fields = ["id", "nom", "stages"] # login_required authentication = EnScolariteAuthentication()