def get_queryset(self): base_queryset = self.get_base_queryset() location = self.get_location() if not location: return base_queryset.none() queryset = base_queryset.annotate(distance=DistanceFunction( "coordinates", location)).order_by("distance") return queryset
def filter_queryset(self, request, queryset, view): if not 'order_by_distance_to' in request.query_params: return queryset try: coordinates = json.loads(request.query_params['order_by_distance_to']) except JSONDecodeError: raise DRFValidationError(detail=self.error_message) if not check_coordinates(coordinates): raise DRFValidationError(detail=self.error_message) return queryset.annotate(distance=DistanceFunction('coordinates', Point(coordinates, srid=4326))).order_by('distance')
def handle( self, event, coordinates, number, distance, departement, region, segment, sentfile, at, exclude_telegram, export_file, **options, ): if (sum(0 if arg is None else 1 for arg in [event, coordinates, departement, region, segment]) != 1): raise CommandError( "Vous devez indiquer soit un événemnet, soit des coordonnées, soit un département, une région ou un segment." ) if (event or coordinates) and number is None and distance is None: raise CommandError( "Vous devez indiquer soit un nombre de personnes, soit une distance max." ) if event: # we generate coordinates from event if event.coordinates is None: raise CommandError( "Cet événement n'a pas de coordonnées géographiques.") coordinates = event.coordinates self.stdout.write(f"Événement : {event.name}") self.stdout.write(event.short_location()) self.stdout.write( event.start_time.astimezone( timezone.get_default_timezone()).strftime( "Le %d/%m/%Y à %H:%M")) self.stdout.write("\n") # ligne vide if coordinates: # two case : central point coordinates or any other ps = (Person.objects.filter(subscribed_sms=True).exclude( contact_phone="").annotate(distance=DistanceFunction( "coordinates", coordinates)).order_by("distance")) if distance is not None: ps = ps.filter(distance__lte=distance) if exclude_telegram: ps = ps.exclude(meta__has_telegram=True) res = list( drop_duplicate_numbers( ((p.contact_phone, p.distance) for p in ps.iterator() if self.can_send(p.contact_phone)), number, )) numbers = [n for n, _ in res] max_distance = res[-1][1] self.stdout.write(f"Distance maximale : {max_distance}") else: if segment: ps = (segment.get_subscribers_queryset().exclude( contact_phone="").distinct()) self.stdout.write(f"Segment : {segment.name}") else: ps = Person.objects.filter( region or departement, subscribed_sms=True).exclude(contact_phone="") if exclude_telegram: ps = ps.exclude(meta__has_telegram=True) numbers = set(p.contact_phone for p in ps.iterator() if self.can_send(p.contact_phone)) self.stdout.write(f"Nombre de numéros : {len(numbers)}") if export_file is not None: export_file.write("\n".join(str(number) for number in numbers)) return if sentfile is not None: sent_numbers = self.read_numbers(sentfile) numbers.difference_update(sent_numbers) self.stdout.write( f"{len(numbers)} après prise en compte des numéros déjà envoyés." ) self.stdout.write("\n") # empty line self.stdout.write( "Entrez votre message (deux lignes vides pour terminer)") message = "" last_line = None while True: current_line = input("") message += "\n" + current_line if current_line == "" and last_line == "": break last_line = current_line message = message.strip() self.stdout.write("Message enregistré") sms_info = compute_sms_length_information(message) self.stdout.write( f"Encodé en {sms_info.encoding}, {len(message)} caractères, {sms_info.byte_length} octets pour un total de" f" {sms_info.messages} SMS.") self.stdout.write("") self.stdout.write("Prêt pour envoi.") answer = "" while answer not in ["ENVOYER", "ANNULER"]: answer = input("Indiquer ENVOYER ou ANNULER : ") if answer == "ANNULER": return token = secrets.token_urlsafe(4) sent_filename = Path(f"sent.{token}") invalid_filename = Path(f"invalid.{token}") try: sent, invalid = send_bulk_sms(message, tqdm(numbers), at=at) except SMSSendException as e: self.stderr.write("Erreur lors de l'envoi des SMS.") self.stderr.write( f"{len(e.sent)} SMS ont déjà été envoyés ({len(e.invalid)} numéros invalides)." ) try: self.write_numbers(sent_filename, e.sent) self.write_numbers(invalid_filename, e.invalid) except OSError: self.stderr.write( "Impossible d'écrire les fichiers avec les numéros testés." ) raise self.stderr.write( f"Fichiers {sent_filename} et {invalid_filename} écrits.") return 1 self.stdout.write(f"{len(sent)} SMS envoyés") if invalid: self.stdout.write(f"{len(invalid)} numéros invalides") self.write_numbers(invalid_filename, invalid) self.stdout.write(f"{invalid_filename} écrit.")
def get_tweets(request): """ Get all the coords + sentiments of tweets in range of the given latlng + distance :param request: :return: """ t1 = time.time() default_limit = 200 default_dist = 1 if not request.GET: return HttpResponse(status=400) else: # If latlng is None, then we get all the data points latlng = request.GET.get('latlng') dist = request.GET.get('dist') limit = request.GET.get('limit') return_text = request.GET.get('return_text') lang = request.GET.get('lang') # Default distance of 1 km if dist is None: dist = default_dist # Default limit of 50 tweets if limit is None: limit = default_limit if return_text is None: return_text = False else: return_text = return_text.lower() == 'true' or str( return_text) == "1" if lang is None: lang = '' try: if latlng is not None: latlng = latlng.split(',') lat = float(latlng[0]) lng = float(latlng[1]) dist = float(dist) limit = int(limit) limit = min(max(limit, 1), default_limit) dist = max(dist, default_dist) except ValueError: return HttpResponse(status=400) if latlng is not None: # see: https://stackoverflow.com/questions/19703975/django-sort-by-distance # and: https://stackoverflow.com/questions/8464666/distance-between-2-points-in-postgis-in-srid-4326-in-metres degrees_distance = round((dist * 0.01), 2) + 0.01 point = Point(lng, lat) tweets = Tweet.objects.filter( coords__dwithin=(point, degrees_distance)).annotate( distance=DistanceFunction('coords', point)).order_by( 'distance') if lang == '': tweets = tweets[:limit] else: tweets = Tweet.objects.filter(coords__isnull=False) if lang != '': tweets = tweets.filter(lang=lang) tweets = tweets[:limit] if return_text: res = [{ 'coords': t.get_coords(), 'tweet_id': t.uid, 'polarity': t.polarity, 'lang': t.lang, 'timestamp': t.timestamp.date(), 'country': t.country, 'text': t.text } for t in tweets] else: res = [{ 'coords': t.get_coords(), 'tweet_id': t.uid, 'polarity': t.polarity, 'lang': t.lang, 'timestamp': t.timestamp.date(), 'country': t.country } for t in tweets] print('Elapsed:', time.time() - t1) return JsonResponse({'tweets': res})