def testUnitAttName(self): "Testing the `unit_attname` class method" unit_tuple = [('Yard', 'yd'), ('Nautical Mile', 'nm'), ('German legal metre', 'german_m'), ('Indian yard', 'indian_yd'), ('Chain (Sears)', 'chain_sears'), ('Chain', 'chain')] for nm, att in unit_tuple: with self.subTest(nm=nm): self.assertEqual(att, D.unit_attname(nm))
def testUnitAttName(self): "Testing the `unit_attname` class method" unit_tuple = [ ("Yard", "yd"), ("Nautical Mile", "nm"), ("German legal metre", "german_m"), ("Indian yard", "indian_yd"), ("Chain (Sears)", "chain_sears"), ("Chain", "chain"), ] for nm, att in unit_tuple: self.assertEqual(att, D.unit_attname(nm))
def test_nearby_query(self): # Creates the available journeys with driver... user1 = UserFactory() residence1 = ResidenceFactory(user=user1, position=Point( 883877.34, 547084.05, srid=DEFAULT_PROJECTED_SRID)) user2 = UserFactory() residence2 = ResidenceFactory(user=user2, position=Point( 882823.07, 545542.48, srid=DEFAULT_PROJECTED_SRID)) campus = CampusFactory() user3 = UserFactory() residence3 = ResidenceFactory(user=user3, position=Point( 865621.24, 545274.90, srid=DEFAULT_PROJECTED_SRID)) JourneyFactory(user=user1, driver=user1, residence=residence1, campus=campus) JourneyFactory(user=user2, driver=user2, residence=residence2, campus=campus) JourneyFactory(user=user3, driver=user3, residence=residence3, campus=campus) point = Point(882532.74, 545437.43, srid=DEFAULT_PROJECTED_SRID) self.assertEquals( Journey.objects.nearby(geometry=point, distance=D(m=2500)).count(), 2)
def get_queryset(self): queryset = ParkingSpot.objects.all() near = self.request.query_params.get('near') distance = self.request.query_params.get('distance') if near: # user has specified a near parameter, looking for # objects within a certain distance; assume distance # is in km try: point = fromstr(near, srid=4326) if distance: try: distance = float(distance) except ValueError: # Default to 2 km. distance = 2 else: distance = 2 queryset = queryset.filter( location__distance_lte=(point, D(km=distance))) except ValueError: # Ignore all the above and just return queryset return queryset return queryset
def get_venue_mapping_for_places(self, places, coordinates=None, radius=None, **kwargs): ident_list = [p['ident'] for p in places] qs = VenueRequest.objects.filter(ident__in=ident_list) if coordinates is not None: point = Point(coordinates[1], coordinates[0]) if radius: radius = int(radius * 0.9) else: radius = 500 qs = qs.union( VenueRequest.objects.exclude( ident__startswith=self.name + ':').filter(geo__isnull=False).filter( geo__dwithin=(point, radius)).filter( geo__distance_lte=(point, D(m=radius)))[:50]) vris = VenueRequestItem.objects.select_related('foirequest') qs = qs.prefetch_related(Prefetch('request_items', queryset=vris)) return {r.ident: r for r in qs}
def run(): # Delete previous data # RoadData_snapped.objects.all().delete() rp = RoadPothole.objects.all() # Seetting the nearest road api search_distance = 50 for r in rp: input_pt = Point(r.point.x, r.point.y) # matched_points = RoadPoint.objects.filter(point__distance_lt=(input_pt,D(m=search_distance))) matched_points = RoadData_snapped.objects.filter( center__distance_lt=(input_pt, D(m=search_distance))) if len(matched_points) != 0: pothole = matched_points[0] pothole.rating = (pothole.rating * pothole.total_potholes + r.rating) / (pothole.total_potholes + 1) pothole.total_potholes = pothole.total_potholes + 1 pothole.save() print(len(RoadData_snapped.objects.all()))
def node_layer_validation(self): """ 1. if minimum distance is specified, ensure node is not too close to other nodes; 2. if layer defines an area, ensure node coordinates are contained in the area """ try: minimum_distance = self.layer.minimum_distance geometry = self.geometry layer_area = self.layer.area except ObjectDoesNotExist: # this happens if node.layer is None return # TODO - lower priority: do this check only when coordinates are changing if minimum_distance > 0: near_nodes = Node.objects.exclude(pk=self.id).filter( geometry__distance_lte=(geometry, D(m=minimum_distance))).count() if near_nodes > 0: raise ValidationError( _('Distance between nodes cannot be less than %s meters') % minimum_distance) if layer_area is not None and not layer_area.contains(geometry): raise ValidationError(_('Node must be inside layer area'))
def get_city(self, name, row, country): cols, cache = self.columns, self.cities iso = country.code if (iso, name) in cache: return cache[(iso, name)] point = Point(float(row[cols['longitude']]), float(row[cols['latitude']])) qs = City.objects.distance(point).filter(country=country) try: c = qs.get( Q(name_std__iexact=name) | Q(name__iexact=name) | Q(alt_names__name__iexact=name)) except (City.DoesNotExist, MultipleObjectsReturned): try: c = qs.exclude(location__distance_gte=(point, D( km=50))).order_by('distance')[0] except IndexError: c = None cache[(iso, name)] = c return c
def get_queryset(self): user = self.request.user miles = self.request.GET.get('miles', 100) distance = D(mi=miles) if user.last_location: queryset = (User.objects.filter( last_location__distance_lte=(user.last_location, distance), ghost_mode=False) | User.objects.filter(featured=True)) last_location = user.last_location else: queryset = User.objects.filter(featured=True) last_location = GEOSGeometry('POINT (0 0)', srid=4326) queryset = queryset.annotate( distance=Distance('last_location', last_location)).exclude( id=self.request.user.id).with_connection_percentage_for_user( user) return queryset.extra( select={'picture_is_null': 'picture is NULL'}, order_by=[ 'picture_is_null', ], )
def end(self, end_position=None): self.rent_end = now() if end_position is not None: self.end_position = end_position elif self.bike.public_geolocation(): self.end_position = self.bike.public_geolocation().geo self.save() if self.end_position: # attach bike to station if location is closer than X meters # distance is configured in preferences max_distance = preferences.BikeSharePreferences.station_match_max_distance station_closer_than_Xm = Station.objects.filter( location__distance_lte=(self.end_position, D(m=max_distance)), status="AC", ).first() if station_closer_than_Xm: self.bike.current_station = station_closer_than_Xm self.end_station = station_closer_than_Xm self.save() else: self.bike.current_station = None # set Bike status back to available self.bike.availability_status = "AV" self.bike.save() try: # set new non static bike ID, so for GBFS observers can not track this bike self.bike.non_static_bike_uuid = uuid.uuid4() self.bike.save() except IntegrityError: # Congratulations! The 2^64 chance of uuid4 collision has happend. # here coul'd be the place for the famous comment: "should never happen" # So we catch this error here, but don't handle it. # because don't rotating a uuid every 18,446,744,073,709,551,615 rents is ok pass
def get(self, request): api_json = {} open_space_id = self.request.query_params.get('id') distance = self.request.query_params.get('distance') print(open_space_id) open_space = OpenSpace.objects.get(id=open_space_id) longitude = open_space.centroid[0] latitude = open_space.centroid[1] openspace_location = GEOSGeometry('POINT({} {})'.format( longitude, latitude), srid=4326) resource_queryset = AvailableFacility.objects \ .filter(location__distance_lte=(openspace_location, D(km=distance))) \ .annotate(distance=Distance('location', openspace_location)) \ .order_by('distance') print(resource_queryset) resource_json = AvailableFacilitySerializer( resource_queryset, many=True, context={'request': request}) json = JSONRenderer().render(resource_json.data) stream = io.BytesIO(json) data = JSONParser().parse(stream) api_json['facility'] = data return Response(api_json)
def filter_queryset(self, request, queryset, view): location_longitude = request.query_params.get('location_longitude', None) location_latitude = request.query_params.get('location_latitude', None) distance_km = request.query_params.get('location_distance_km', None) if location_longitude and location_latitude and distance_km: pnt = GEOSGeometry( 'POINT({0} {1})'.format( location_longitude, location_latitude), srid=4326) if Location is not queryset.model: model_prefix = 'location__' else: model_prefix = '' loc_ids = Location.objects.filter( **{'point_pos__distance_lte': (pnt, D(km=distance_km))}).values('id') return queryset.filter(**{"{}id__in".format(model_prefix): loc_ids}) return queryset
def get(self, request): geo = request.GET['geo'] dis = request.GET['dis'] traj = self.q.filter(geom__distance_lte=(geo, D(m=dis))) count = traj.count() response = {} if (request.GET['has_time'] == 'true'): timeStartStr = request.GET['start_time'] timeStart = datetime.strptime(timeStartStr, '%H:%M') timeEndStr = request.GET['end_time'] timeEnd = datetime.strptime(timeEndStr, '%H:%M') traj = traj.filter( Q(start_time__range=(timeStart, timeEnd)) | Q(end_time__range=(timeStart, timeEnd))) count = traj.count() response['lineset'] = serialize('geojson', traj) response['count'] = count return HttpResponse( json.dumps(response), content_type="application/json", )
def test_dwithin_gis_lookup_output_with_rasters(self): """ Check the logical functionality of the dwithin lookup for different input parameters. """ # Create test raster and geom. rast = GDALRaster(json.loads(JSON_RASTER)) stx_pnt = GEOSGeometry( 'POINT (-95.370401017314293 29.704867409475465)', 4326) stx_pnt.transform(3086) # Filter raster with different lookup raster formats. qs = RasterModel.objects.filter(rastprojected__dwithin=(rast, D(km=1))) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter( rastprojected__dwithin=(json.loads(JSON_RASTER), D(km=1))) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rastprojected__dwithin=(JSON_RASTER, D(km=1))) self.assertEqual(qs.count(), 1) # Filter in an unprojected coordinate system. qs = RasterModel.objects.filter(rast__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) # Filter with band index transform. qs = RasterModel.objects.filter(rast__1__dwithin=(rast, 1, 40)) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rast__1__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rast__dwithin=(rast, 1, 40)) self.assertEqual(qs.count(), 1) # Filter raster by geom. qs = RasterModel.objects.filter(rast__dwithin=(stx_pnt, 500)) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rastprojected__dwithin=(stx_pnt, D(km=10000))) self.assertEqual(qs.count(), 1) qs = RasterModel.objects.filter(rast__dwithin=(stx_pnt, 5)) self.assertEqual(qs.count(), 0) qs = RasterModel.objects.filter(rastprojected__dwithin=(stx_pnt, D(km=100))) self.assertEqual(qs.count(), 0) # Filter geom by raster. qs = RasterModel.objects.filter(geom__dwithin=(rast, 500)) self.assertEqual(qs.count(), 1) # Filter through related model. qs = RasterRelatedModel.objects.filter( rastermodel__rast__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) # Filter through related model with band index transform qs = RasterRelatedModel.objects.filter( rastermodel__rast__1__dwithin=(rast, 40)) self.assertEqual(qs.count(), 1) # Filter through conditional statements. qs = RasterModel.objects.filter( Q(rast__dwithin=(rast, 40)) & Q(rastprojected__dwithin=(stx_pnt, D(km=10000)))) self.assertEqual(qs.count(), 1) # Filter through different lookup. qs = RasterModel.objects.filter(rastprojected__bbcontains=rast) self.assertEqual(qs.count(), 1)
def refine(self): self._update() constraints = self.triconstraint_set.all().order_by('rtt') af = 4 if re.search(':', self.ip): af = 6 msm_def = { "definitions": [{ "target": self.ip, "description": "triangulation for %s" % self.ip, "type": "ping", "af": af, "is_oneoff": True, "packets": 5, }], "probes": [] } if len(constraints) == 0: ## no previous knowledge on this IP ### add 5 probes from each 'area' for area in ('West', 'North-Central', 'South-Central', 'North-East', 'South-East'): msm_def['probes'].append({ 'requested': 5, 'type': 'area', 'value': area }) else: prb_set = Probe.objects.all() loc_set = Loc.objects.all().order_by('-pop') for c in constraints: max_dist = c.rtt * self.__class__.KM_PER_MS point_rep = 'POINT(%s %s)' % (c.lon, c.lat) prb_set = prb_set.filter(point__distance_lt=(point_rep, D(km=max_dist))) loc_set = loc_set.filter(point__distance_lt=(point_rep, D(km=max_dist))) print "potential locs within constraints %s" % (len(loc_set)) ## top 5 locs within set (for now ordered by population) prb_ids = [] for loc in loc_set: ## select 3 probes close to this loc prb_close_to_loc = Probe.objects.filter( point__distance_lt=('POINT(%s %s)' % (loc.lon, loc.lat), D(km=100))).order_by('-id') for p in prb_close_to_loc[0:3]: prb_ids.append(str(p.id)) print "added %s (%s)" % (p.id, loc) if len(prb_ids) > 20: break msm_def['probes'].append({ 'requested': 20, 'type': 'probes', 'value': ",".join(prb_ids) }) msm_json = json.dumps(msm_def) msm_req = JsonRequest(self.__class__.msm_create_url) try: msm_conn = urllib2.urlopen(msm_req, msm_json) except urllib2.HTTPError as e: print "HTTP error %s " % (e.read) msm_meta = json.load(msm_conn) for msm_id in msm_meta['measurements']: self.save() new_trimsm = self.trimsm_set.create(msm=msm_id) print "msm_id created: %s" % (msm_id)
def test05_geodetic_distance_lookups(self): "Testing distance lookups on geodetic coordinate systems." # Line is from Canberra to Sydney. Query is for all other cities within # a 100km of that line (which should exclude only Hobart & Adelaide). line = GEOSGeometry('LINESTRING(144.9630 -37.8143,151.2607 -33.8870)', 4326) dist_qs = AustraliaCity.objects.filter(point__distance_lte=(line, D(km=100))) if oracle or connection.ops.geography: # Oracle and PostGIS 1.5 can do distance lookups on arbitrary geometries. self.assertEqual(9, dist_qs.count()) self.assertEqual([ 'Batemans Bay', 'Canberra', 'Hillsdale', 'Melbourne', 'Mittagong', 'Shellharbour', 'Sydney', 'Thirroul', 'Wollongong' ], self.get_names(dist_qs)) else: # PostGIS 1.4 and below only allows geodetic distance queries (utilizing # ST_Distance_Sphere/ST_Distance_Spheroid) from Points to PointFields # on geometry columns. self.assertRaises(ValueError, dist_qs.count) # Ensured that a ValueError was raised, none of the rest of the test is # support on this backend, so bail now. if spatialite: return # Too many params (4 in this case) should raise a ValueError. self.assertRaises( ValueError, len, AustraliaCity.objects.filter(point__distance_lte=('POINT(5 23)', D(km=100), 'spheroid', '4'))) # Not enough params should raise a ValueError. self.assertRaises( ValueError, len, AustraliaCity.objects.filter( point__distance_lte=('POINT(5 23)', ))) # Getting all cities w/in 550 miles of Hobart. hobart = AustraliaCity.objects.get(name='Hobart') qs = AustraliaCity.objects.exclude(name='Hobart').filter( point__distance_lte=(hobart.point, D(mi=550))) cities = self.get_names(qs) self.assertEqual(cities, ['Batemans Bay', 'Canberra', 'Melbourne']) # Cities that are either really close or really far from Wollongong -- # and using different units of distance. wollongong = AustraliaCity.objects.get(name='Wollongong') d1, d2 = D(yd=19500), D(nm=400) # Yards (~17km) & Nautical miles. # Normal geodetic distance lookup (uses `distance_sphere` on PostGIS. gq1 = Q(point__distance_lte=(wollongong.point, d1)) gq2 = Q(point__distance_gte=(wollongong.point, d2)) qs1 = AustraliaCity.objects.exclude(name='Wollongong').filter(gq1 | gq2) # Geodetic distance lookup but telling GeoDjango to use `distance_spheroid` # instead (we should get the same results b/c accuracy variance won't matter # in this test case). if postgis: gq3 = Q(point__distance_lte=(wollongong.point, d1, 'spheroid')) gq4 = Q(point__distance_gte=(wollongong.point, d2, 'spheroid')) qs2 = AustraliaCity.objects.exclude( name='Wollongong').filter(gq3 | gq4) querysets = [qs1, qs2] else: querysets = [qs1] for qs in querysets: cities = self.get_names(qs) self.assertEqual( cities, ['Adelaide', 'Hobart', 'Shellharbour', 'Thirroul'])
def test_all_gis_lookups_with_rasters(self): """ Evaluate all possible lookups for all input combinations (i.e. raster-raster, raster-geom, geom-raster) and for projected and unprojected coordinate systems. This test just checks that the lookup can be called, but doesn't check if the result makes logical sense. """ from django.contrib.gis.db.backends.postgis.operations import PostGISOperations # Create test raster and geom. rast = GDALRaster(json.loads(JSON_RASTER)) stx_pnt = GEOSGeometry( 'POINT (-95.370401017314293 29.704867409475465)', 4326) stx_pnt.transform(3086) lookups = [(name, lookup) for name, lookup in BaseSpatialField.get_lookups().items() if issubclass(lookup, GISLookup)] self.assertNotEqual(lookups, [], 'No lookups found') # Loop through all the GIS lookups. for name, lookup in lookups: # Construct lookup filter strings. combo_keys = [ field + name for field in [ 'rast__', 'rast__', 'rastprojected__0__', 'rast__', 'rastprojected__', 'geom__', 'rast__', ] ] if issubclass(lookup, DistanceLookupBase): # Set lookup values for distance lookups. combo_values = [ (rast, 50, 'spheroid'), (rast, 0, 50, 'spheroid'), (rast, 0, D(km=1)), (stx_pnt, 0, 500), (stx_pnt, D(km=1000)), (rast, 500), (json.loads(JSON_RASTER), 500), ] elif name == 'relate': # Set lookup values for the relate lookup. combo_values = [ (rast, 'T*T***FF*'), (rast, 0, 'T*T***FF*'), (rast, 0, 'T*T***FF*'), (stx_pnt, 0, 'T*T***FF*'), (stx_pnt, 'T*T***FF*'), (rast, 'T*T***FF*'), (json.loads(JSON_RASTER), 'T*T***FF*'), ] elif name == 'isvalid': # The isvalid lookup doesn't make sense for rasters. continue elif PostGISOperations.gis_operators[name].func: # Set lookup values for all function based operators. combo_values = [ rast, (rast, 0), (rast, 0), (stx_pnt, 0), stx_pnt, rast, json.loads(JSON_RASTER) ] else: # Override band lookup for these, as it's not supported. combo_keys[2] = 'rastprojected__' + name # Set lookup values for all other operators. combo_values = [ rast, None, rast, stx_pnt, stx_pnt, rast, json.loads(JSON_RASTER) ] # Create query filter combinations. self.assertEqual( len(combo_keys), len(combo_values), 'Number of lookup names and values should be the same', ) combos = [x for x in zip(combo_keys, combo_values) if x[1]] self.assertEqual( [(n, x) for n, x in enumerate(combos) if x in combos[:n]], [], 'There are repeated test lookups', ) combos = [{k: v} for k, v in combos] for combo in combos: # Apply this query filter. qs = RasterModel.objects.filter(**combo) # Evaluate normal filter qs. self.assertIn(qs.count(), [0, 1]) # Evaluate on conditional Q expressions. qs = RasterModel.objects.filter(Q(**combos[0]) & Q(**combos[1])) self.assertIn(qs.count(), [0, 1])
def within(self, point, distance_km): return self.filter(coords__dwithin=(point, D(km=distance_km)))
def formated_distance(self): ''' :return: Formated distance in KM ''' return D(m=self.distance).km
def get_queryset(self): products = Product.objects.filter(active=1, deleted=0, company__deleted=0, company__active=1) company_id = self.request.GET.get('company_id') if company_id: products = products.filter(company__id=company_id) name = self.request.GET.get('q') if name: products = products.filter(name__icontains=name) medicament_type = self.request.GET.get('medicament_type') if medicament_type: types = medicament_type.split(',') products = products.filter(medicament_type__in=types) lat = self.request.GET.get('lat');lon = self.request.GET.get('lon'); if lat and lon: point = 'POINT(%s %s)' % (lat, lon) pnt = GEOSGeometry(point, srid=4326) products = products.filter(company__address__location__distance_lte=(pnt, D(km=5))) order = self.request.GET.get('order') or 'distance' if order == 'medicament_type': products = products.order_by('medicament_type') elif order == 'lowest_price': products = products.order_by('price') elif order == 'distance' and lat and lon: products = products.distance(pnt, field_name='company__address__location').order_by('distance') limit = self.request.GET.get('limit') or 20 return products[:limit]
def get_tags(self, location, num_tags=10, max_dist=4000, max_weight=4.0, min_weight=1.0, include_system=False): ''' Returns an ordered list of tags based on a location, with the higher tags being more geographically relevant. The algorithm works as follows All tags within the radius of max_dist are considered. Each tag is given a weight based on location, which is determined linearly by the distance from the center, i.e. a tag directly on the given location would be given the maximum weight, while a tag directly on the perimiter of the circle would be given the minimum. All of the weights for a single semantic tag are aggregated into a final score, which is then used to order the tags returned. Arguments: location A tuple formatted as follows (lon, lat) num_tags Number of tags to return max_dist The maximum distance within which to consider tags max_weight The maximum float weight to assign tags closest to the center min_weight The float to assign tags furthest from the center, within the max_dist include_system Wether or not to include system tags ''' center = Point(location[0], location[1]) # max_dist is now a distance object max_dist = D(m=max_dist) # Get all contents within max_dist radius, and get them back in 'distance' format contents = self.content_model.objects.filter( location__distance_lte=(center, max_dist)).distance(center) # max_dist is now a float of meters max_dist = max_dist.m weighted_tags = {} for content in contents: # distance is appended to content by the distance() queryset method dist = content.distance.m # Get the weight for all tags for this content # Weight between 1-4 where 1 is maximum distance and 4 is 0 distance weight = (((max_dist - dist) / max_dist) * (max_weight - min_weight)) + min_weight if include_system: tagqueryset = content.tags.all() else: tagqueryset = content.tags.filter(system_tag=False) for tagobj in tagqueryset: tag = tagobj.name if tag in weighted_tags: weighted_tags[tag] += weight else: weighted_tags[tag] = weight # Sorting dicts by value: http://www.python.org/dev/peps/pep-0265/ recommended_tags = sorted(weighted_tags, key=weighted_tags.__getitem__, reverse=True)[:num_tags] return recommended_tags
def get_queryset(self): ''' query_params: - med_ids: list of MedicaitonName ids - dosages: list of Dosage ids - localization: list of 2 coordinates (must be int or float) - distance: int, in miles ''' med_ids = self.request.query_params.getlist('med_ids[]', None) dosages = self.request.query_params.getlist('dosages[]', None) location = self.request.query_params.get('localization') distance = self.request.query_params.get('distance') # 1 - validate location try: location = list(map(float, location.split(','))) location_point = Point( location[0], location[1], srid=4326, ) except (IndexError, ValueError, AttributeError): raise BadRequest( 'Location should be provided and be a list of 2 coordinates') # 2 - fetch ndc codes from filters: med id and dosage + support for all if len(med_ids) == 1 and med_ids[0] == 'all': med_ndc_qs = MedicationMedicationNameMedicationDosageThrough.objects.all( ) else: med_ndc_qs = MedicationMedicationNameMedicationDosageThrough.objects.filter( medication_name_id__in=med_ids, medication_dosage_id__in=dosages) med_ndc_ids = med_ndc_qs.select_related( 'medication__ndc_codes', ).distinct().values_list( 'medication__ndc_codes', flat=True) # 2 - fetch provider medication entries (supply levels) for the ndc ndc_codes # and filter by distance provider_medication_ids = ProviderMedicationNdcThrough.objects.filter( latest=True, medication_ndc_id__in=med_ndc_ids, provider__geo_localization__distance_lte=( location_point, D(mi=distance), ), ).values_list( 'id', flat=True, ) # SPECIAL INSTRUCTION # Exclude providers from vaccine finder organization ID 4504 (4383 in medfinder) # vaccine finder type needs to be 4 (pharamacy), exclude all other # More info at https://www.pivotaltracker.com/story/show/162711148 provider_qs = Provider.objects.filter( Q(organization_id=4383) | Q(vaccine_finder_type=4) ).filter(geo_localization__distance_lte=( location_point, D(mi=distance), ), ).annotate( distance=Distance( 'geo_localization', location_point, ), total_supply=Coalesce( Sum( 'provider_medication__level', filter=Q( provider_medication__id__in=provider_medication_ids, provider_medication__latest=True, active=True, ), ), 0, ), amount_medications=Count( 'provider_medication', filter=Q( provider_medication__id__in=provider_medication_ids, provider_medication__latest=True, active=True, ), )).prefetch_related( Prefetch( 'provider_medication', queryset=ProviderMedicationNdcThrough.objects.filter( latest=True, id__in=provider_medication_ids, ).select_related( 'medication_ndc__medication', 'medication_ndc__medication__medication_name', ).order_by( '-level', '-medication_ndc__medication__drug_type'))).order_by( '-total_supply', '-active', '-amount_medications', 'distance') return provider_qs
def testAccess(self): "Testing access in different units" d = D(m=100) self.assertEqual(d.km, 0.1) self.assertAlmostEqual(d.ft, 328.084, 3)
def get_nearby(self, radius, lat, lng): """Returns places nearby the given lat/lng within the given radius.""" pnt = Point(float(lng), float(lat)) places = self.get_query_set().filter( point__distance_lte=(pnt, D(km=radius))).distance(pnt) return places
def test_geodetic_distance_lookups(self): """ Test distance lookups on geodetic coordinate systems. """ # Line is from Canberra to Sydney. Query is for all other cities within # a 100km of that line (which should exclude only Hobart & Adelaide). line = GEOSGeometry('LINESTRING(144.9630 -37.8143,151.2607 -33.8870)', 4326) dist_qs = AustraliaCity.objects.filter(point__distance_lte=(line, D(km=100))) expected_cities = [ 'Batemans Bay', 'Canberra', 'Hillsdale', 'Melbourne', 'Mittagong', 'Shellharbour', 'Sydney', 'Thirroul', 'Wollongong', ] if spatialite: # SpatiaLite is less accurate and returns 102.8km for Batemans Bay. expected_cities.pop(0) self.assertEqual(expected_cities, self.get_names(dist_qs)) # Too many params (4 in this case) should raise a ValueError. queryset = AustraliaCity.objects.filter( point__distance_lte=('POINT(5 23)', D(km=100), 'spheroid', '4')) with self.assertRaises(ValueError): len(queryset) # Not enough params should raise a ValueError. with self.assertRaises(ValueError): len( AustraliaCity.objects.filter( point__distance_lte=('POINT(5 23)', ))) # Getting all cities w/in 550 miles of Hobart. hobart = AustraliaCity.objects.get(name='Hobart') qs = AustraliaCity.objects.exclude(name='Hobart').filter( point__distance_lte=(hobart.point, D(mi=550))) cities = self.get_names(qs) self.assertEqual(cities, ['Batemans Bay', 'Canberra', 'Melbourne']) # Cities that are either really close or really far from Wollongong -- # and using different units of distance. wollongong = AustraliaCity.objects.get(name='Wollongong') d1, d2 = D(yd=19500), D(nm=400) # Yards (~17km) & Nautical miles. # Normal geodetic distance lookup (uses `distance_sphere` on PostGIS. gq1 = Q(point__distance_lte=(wollongong.point, d1)) gq2 = Q(point__distance_gte=(wollongong.point, d2)) qs1 = AustraliaCity.objects.exclude(name='Wollongong').filter(gq1 | gq2) # Geodetic distance lookup but telling GeoDjango to use `distance_spheroid` # instead (we should get the same results b/c accuracy variance won't matter # in this test case). querysets = [qs1] if connection.features.has_DistanceSpheroid_function: gq3 = Q(point__distance_lte=(wollongong.point, d1, 'spheroid')) gq4 = Q(point__distance_gte=(wollongong.point, d2, 'spheroid')) qs2 = AustraliaCity.objects.exclude( name='Wollongong').filter(gq3 | gq4) querysets.append(qs2) for qs in querysets: cities = self.get_names(qs) self.assertEqual( cities, ['Adelaide', 'Hobart', 'Shellharbour', 'Thirroul'])
def within(self, point, distance_km): return ( self.filter(coords__distance_lte=(point, D(km=distance_km))) .annotate(distance=Distance("coords", point)) .order_by("distance") )
def testInitInvalid(self): "Testing initialization from invalid units" with self.assertRaises(AttributeError): D(banana=100)
def send_mail_compatible_donors(donation_id): donation = Donation.objects.get(pk=donation_id) compatible_blood_types = donation.get_compatible_blood_types() compatible_donors = UserProfile.objects.filter(position__distance_lte=(donation.position, D(m=100000))).distance( donation.position).filter(reduce(or_, [Q(blood_type=b) for b, d in compatible_blood_types])) email_subject = _(u'Precisa-se de doadores %s em %s' % (donation.get_compatible_blood_types_formatted(), donation.location)) email_from = settings.DEFAULT_FROM_EMAIL email_body = render_to_string('donations/donation_request_email.txt', {'donation_id': donation.id, 'receiver_name': donation.receiver_name, 'compatible_blood_types': donation.get_compatible_blood_types_formatted( ), 'expiration_date': donation.expiration_date, 'donation_center': donation.donation_center, 'location': donation.location}) email_messages = () for donor in compatible_donors: email_messages += ((email_subject, email_body, email_from, [donor.user.email]),) send_mass_mail(email_messages)
def testAccessInvalid(self): "Testing access in invalid units" d = D(m=100) self.assertFalse(hasattr(d, 'banana'))
def test_mysql_geodetic_distance_error(self): msg = 'Only numeric values of degree units are allowed on geodetic distance queries.' with self.assertRaisesMessage(ValueError, msg): AustraliaCity.objects.filter(point__distance_lte=(Point(0, 0), D(m=100))).exists()
def get_queryset(self): longitude = self.request.query_params.get('longitude', None) latitude = self.request.query_params.get('latitude', None) global_tips = Tip.objects.filter( Q(cities=None) & Q(subregions=None) & Q(regions=None) & Q(countries=None)).distinct() if not (longitude and latitude): queryset = global_tips closest_city = None else: location = Point(float(longitude), float(latitude)) close_cities = City.objects.filter( location__distance_lte=(location, D(km=50))).annotate( distance=Distance('location', location)) close_cities = close_cities.order_by('distance')[:10] closest_city = close_cities.first() close_cities = close_cities[1:] logger.debug("Looking tips in nearby cities %s", close_cities) logger.debug("Closest city is %s", closest_city) local_tips = Tip.objects.filter( Q(cities=closest_city) | Q(cities__in=close_cities) | Q(subregions=closest_city.subregion) | Q(regions=closest_city.region) | Q(countries=closest_city.region.country)).distinct() queryset = (local_tips | global_tips).distinct() if closest_city: queryset = queryset.annotate( closest_city_score=Case(When(cities=closest_city, then=(F('score') + 1) * 200), default=0, output_field=IntegerField()), close_cities_score=Case(When(cities__in=close_cities, then=(F('score') + 1) * 100), default=0, output_field=IntegerField()), close_subregions_score=Case(When( subregions=closest_city.subregion, then=(F('score') + 1) * 50), default=0, output_field=IntegerField()), close_regions_score=Case(When(regions=closest_city.region, then=(F('score') + 1) * 20), default=0, output_field=IntegerField()), close_countries_score=Case(When( countries=closest_city.region.country, then=(F('score') + 1) * 10), default=0, output_field=IntegerField())) queryset = queryset.annotate( boost_score=(F('score') + F('closest_city_score') + F('close_cities_score') + F('close_subregions_score') + F('close_regions_score') + F('close_countries_score'))) return queryset.order_by('-boost_score', 'id').prefetch_related( 'cities', 'subregions', 'regions', 'countries').distinct() else: return queryset.order_by('-score').distinct()
def test_distance_function_d_lookup(self): qs = Interstate.objects.annotate( d=Distance(Point(0, 0, srid=3857), Point(0, 1, srid=3857)), ).filter(d=D(m=1)) self.assertTrue(qs.exists())