public
Description: A generic, easy-to-use location-awareness application built for use in Django projects.
Homepage: http://django-geo.googlecode.com/
Clone URL: git://github.com/obeattie/django-geo.git
1.1 Release
oliver@obeattie.com (author)
Sun Jan 27 04:35:06 -0800 2008
commit  9443ecc68ac3b72637f8364b5a1280690a1b3807
tree    cbbd1a5c6830d890548907d9c2d100602e669ed6
parent  5bcf6a3b7e1296317d407d7552ad9dbd9fbe872d
...
5
6
7
 
 
8
9
10
...
43
44
45
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
...
5
6
7
8
9
10
11
12
...
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
0
@@ -5,6 +5,8 @@ try:
0
 except ImportError:
0
   import pickle
0
 
0
+import base64
0
+
0
 class PickledObject(str):
0
   """A subclass of string so it can be told whether a string is
0
    a pickled object or not (if the object is an instance of this class
0
@@ -43,3 +45,73 @@ class PickledObjectField(models.Field):
0
       return super(PickledObjectField, self).get_db_prep_lookup(lookup_type, value)
0
     else:
0
       raise TypeError('Lookup type %s is not supported.' % lookup_type)
0
+
0
+class DictionaryField(models.Field):
0
+ # Django seems to do some funky stuff prohibiting this class from inheriting from
0
+ # PickledObjectField which I can't be bothered to explore. This is quicker, but not DRY :-(
0
+ __metaclass__ = models.SubfieldBase
0
+
0
+ def to_python(self, value):
0
+ if isinstance(value, dict):
0
+ return value
0
+ else:
0
+ if not value:
0
+ return value
0
+ return pickle.loads(str(value))
0
+
0
+ def get_db_prep_save(self, value):
0
+ if value is not None and not isinstance(value, basestring):
0
+ if isinstance(value, dict):
0
+ value = pickle.dumps(value)
0
+ else:
0
+ raise TypeError('This field can only store dictionaries. Use PickledObjectField to store a wide(r) range of data types.')
0
+ return value
0
+
0
+ def get_internal_type(self):
0
+ return 'TextField'
0
+
0
+ def get_db_prep_lookup(self, lookup_type, value):
0
+ if lookup_type == 'exact':
0
+ value = self.get_db_prep_save(value)
0
+ return super(DictionaryField, self).get_db_prep_lookup(lookup_type, value)
0
+ elif lookup_type == 'in':
0
+ value = [self.get_db_prep_save(v) for v in value]
0
+ return super(DictionaryField, self).get_db_prep_lookup(lookup_type, value)
0
+ else:
0
+ raise TypeError('Lookup type %s is not supported.' % lookup_type)
0
+
0
+class ListField(models.Field):
0
+ """A field for storing a list (or tuple) in the database."""
0
+ __metaclass__ = models.SubfieldBase
0
+
0
+ def to_python(self, value):
0
+ if isinstance(value, (list, tuple)):
0
+ return value
0
+ else:
0
+ if not value:
0
+ return value
0
+ try:
0
+ return base64.b64decode(pickle.loads(str(value)))
0
+ except:
0
+ return []
0
+
0
+ def get_db_prep_save(self, value):
0
+ if value is not None and not isinstance(value, basestring):
0
+ if isinstance(value, (list, tuple)):
0
+ value = base64.b64encode(pickle.dumps(value))
0
+ else:
0
+ raise TypeError('This field can only store lists or tuples. Use PickledObjectField to store a wide(r) range of data types.')
0
+ return value
0
+
0
+ def get_internal_type(self):
0
+ return 'TextField'
0
+
0
+ def get_db_prep_lookup(self, lookup_type, value):
0
+ if lookup_type == 'exact':
0
+ value = self.get_db_prep_save(value)
0
+ return super(DictionaryField, self).get_db_prep_lookup(lookup_type, value)
0
+ elif lookup_type == 'in':
0
+ value = [self.get_db_prep_save(v) for v in value]
0
+ return super(DictionaryField, self).get_db_prep_lookup(lookup_type, value)
0
+ else:
0
+ raise TypeError('Lookup type %s is not supported.' % lookup_type)
0
\ No newline at end of file
...
261
262
263
264
265
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
...
261
262
263
 
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
0
@@ -261,4 +261,23 @@ def base_cmp_by_proximity(current, previous, coords):
0
     return 1
0
 
0
 class GeocodingError(Exception):
0
- pass
0
\ No newline at end of file
0
+ pass
0
+
0
+google_map_types = {
0
+ 'standard': 'G_NORMAL_MAP',
0
+ 'normal': 'G_NORMAL_MAP',
0
+ 'street': 'G_NORMAL_MAP',
0
+ 'satellite': 'G_SATELLITE_MAP',
0
+ 'hybrid': 'G_HYBRID_MAP',
0
+}
0
+
0
+yahoo_precision_to_google_zoom_mappings = {
0
+ 'address': 17,
0
+ 'street': 16,
0
+ 'zip+4': 15,
0
+ 'zip+2': 14,
0
+ 'zip': 13,
0
+ 'city': 11,
0
+ 'state': 9,
0
+ 'country': 3,
0
+}
0
\ No newline at end of file
...
1
2
3
4
5
6
7
 
8
9
10
11
12
13
14
15
16
 
 
 
 
17
18
19
20
 
21
22
23
...
35
36
37
38
 
39
40
 
41
42
43
...
48
49
50
51
 
52
53
54
...
58
59
60
61
62
 
 
63
64
65
66
67
 
 
68
69
70
 
71
72
 
73
74
75
76
77
78
79
80
81
82
 
 
83
84
 
 
85
86
87
88
 
 
 
89
90
91
...
94
95
96
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
98
99
100
101
102
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
105
106
107
108
109
 
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
 
 
 
152
153
154
155
 
 
 
 
 
 
 
 
 
156
157
 
 
 
 
 
 
 
 
 
 
 
158
 
 
 
 
 
 
 
159
160
161
162
163
 
 
164
165
166
...
170
171
172
173
 
174
175
176
 
177
...
 
1
 
 
 
 
 
2
3
 
 
4
 
 
 
 
 
5
6
7
8
9
10
11
 
12
13
14
15
...
27
28
29
 
30
31
 
32
33
34
35
...
40
41
42
 
43
44
45
46
...
50
51
52
 
 
53
54
55
56
57
 
 
58
59
60
61
 
62
63
 
64
65
66
 
 
 
 
 
 
 
 
67
68
69
 
70
71
72
73
 
 
74
75
76
77
78
79
...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
 
 
 
 
 
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
 
124
125
126
127
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
129
130
131
132
133
 
134
135
136
137
138
139
140
141
142
143
 
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
 
 
 
165
166
167
168
169
...
173
174
175
 
176
177
178
 
179
180
0
@@ -1,23 +1,15 @@
0
-from django.db import models
0
 import datetime
0
-try:
0
- import cPickle as pickle
0
-except ImportError:
0
- import pickle
0
-# Imports for Django stuff
0
+from geopy import distance as geopy_distance
0
 from django.db import models
0
-from django.utils.encoding import smart_unicode
0
-from django.core.exceptions import ObjectDoesNotExist
0
 from django.conf import settings
0
-# Imports for geo stuff
0
-from wt.generic.geo import misc as geo_misc
0
-from wt.generic.geo import fields as custom_fields
0
-from wt.generic.geo.dateutil import relativedelta
0
-from geopy import geocoders as geopy_geocoders, distance as geopy_distance
0
+
0
+from geo import fields as custom_fields
0
+from geo import geocoding, misc
0
+from geo.dateutil.relativedelta import relativedelta
0
 
0
 class LocationManager(models.Manager):
0
   def by_proximity_to_location(self, origin_location, radius_miles=None):
0
- """Returns a list of all Location objects (excluding the origin_location)
0
+ """Returns a list of all self.model objects (excluding the origin_location)
0
       within radius_miles miles of the passed location if specified (otherwise
0
       returns all other objects), ordered by ascending proximity to it."""
0
     
0
@@ -35,9 +27,9 @@ class LocationManager(models.Manager):
0
         },
0
       }
0
     
0
- results = Location.objects.filter(latitude__range=(coord_set['latitude']['minimum'], coord_set['latitude']['maximum'])).filter(longitude__range=(coord_set['longitude']['minimum'], coord_set['longitude']['maximum']))
0
+ results = self.model.objects.filter(latitude__range=(coord_set['latitude']['minimum'], coord_set['latitude']['maximum'])).filter(longitude__range=(coord_set['longitude']['minimum'], coord_set['longitude']['maximum']))
0
     else:
0
- results = Location.objects.all()
0
+ results = self.model.objects.all()
0
     
0
     # Exclude any locations with exactly the same co-ordinates (GeoPy doesn't play nice with these)
0
     results = list(results.exclude(latitude__exact=origin_location.latitude).exclude(longitude__exact=origin_location.longitude))
0
@@ -48,7 +40,7 @@ class LocationManager(models.Manager):
0
           results.remove(result)
0
     
0
     def proximity_cmp(current, previous, location=origin_location):
0
- return geo_misc.base_cmp_by_proximity(current, previous, location.coords_tuple)
0
+ return misc.base_cmp_by_proximity(current, previous, location.coords_tuple)
0
     
0
     results.sort(proximity_cmp)
0
     return results
0
@@ -58,34 +50,30 @@ class LocationManager(models.Manager):
0
   
0
   @property
0
   def public(self):
0
- """Returns all Location objects which have is_public set as True (convenience function)."""
0
- return Location.objects.filter(is_public=True)
0
+ """Returns all self.model objects which have is_public set as True (convenience function)."""
0
+ return self.model.objects.filter(is_public=True)
0
   
0
   @property
0
   def expired(self):
0
- """Returns all Location objects which have expired (convenience function)."""
0
- return Location.objects.filter(refreshed__lte=(datetime.datetime.now() - relativedelta.relativedelta(**settings.MAX_LOCATION_CACHE_AGE)))
0
+ """Returns all self.model objects which have expired (convenience function)."""
0
+ return self.model.objects.filter(refreshed__lte=(datetime.datetime.now() - relativedelta.relativedelta(**settings.MAX_LOCATION_CACHE_AGE)))
0
   
0
   def within_bounds(self, north_west, south_east):
0
- """Returns a QuerySet of Locations within the supplied lat/long two-tuples (the northwest
0
+ """Returns a QuerySet of self.models within the supplied lat/long two-tuples (the northwest
0
      and southwest-most corners bounding the segment of the earth in which to search)."""
0
- return Location.objects.filter(latitude__range=(north_west[0], south_east[0])).filter(longitude__range=(north_west[1], south_east[1]))
0
+ return self.model.objects.filter(latitude__range=(north_west[0], south_east[0])).filter(longitude__range=(north_west[1], south_east[1]))
0
 
0
 class Location(models.Model):
0
- """Defines a location somewhere on the globe (presumably! [somewhere with two-
0
- dimensional space defined by latitude/longitude anyway!]). All that needs
0
- to be entered is a query, which is what will be geocoded (for example
0
- 'Penzance, UK'), and everything else will be taken care of automagically.
0
- Note that if the object is to be used before it is saved, then
0
- refresh_if_needed needs to be called."""
0
-
0
- query = models.TextField('Location', blank=False, null=False) # TextField in case it's over 250 characters
0
+ """A Location on the earth."""
0
+ query = models.CharField('Location', max_length=250, blank=False, null=False, unique=True)
0
   friendly_name = models.CharField(max_length=250, blank=True, null=True, help_text='Use this to assign a friendly display-name to this location like \'Home\'.')
0
- geocoder = custom_fields.PickledObjectField(blank=True, null=False)
0
+ geocoded = models.BooleanField(default=True)
0
+ result = custom_fields.PickledObjectField(blank=True, null=True, editable=False)
0
   latitude = models.FloatField(blank=True, null=False)
0
   longitude = models.FloatField(blank=True, null=False)
0
- refreshed = models.DateTimeField(editable=False, blank=True, null=False)
0
- created = models.DateTimeField(editable=False, blank=True, null=True)
0
+ refreshed = models.DateTimeField(editable=False, blank=True, null=False, default=datetime.datetime.now())
0
+ extra = custom_fields.DictionaryField('A dictionary of additional information', blank=True, null=True, editable=False)
0
+ created = models.DateTimeField(editable=False, blank=True, null=True, default=datetime.datetime.now())
0
   is_public = models.BooleanField(default=True)
0
   # Manager
0
   objects = LocationManager()
0
@@ -94,73 +82,88 @@ class Location(models.Model):
0
     list_display = ('__str__', 'latitude', 'longitude', 'created', 'refreshed')
0
     list_filter = ('created', 'refreshed')
0
   
0
+ def save(self, *args, **kwargs):
0
+ self.refresh()
0
+ return super(Location, self).save(*args, **kwargs)
0
+
0
+ # General
0
+ def __unicode__(self):
0
+ return unicode(self.name)
0
+
0
+ def __getitem__(self, index):
0
+ """Gets either a latitude or longitude by indexing the coords_tuple."""
0
+ return self.coords_tuple[index]
0
+
0
+ def get_geocoder(self):
0
+ """Returns an instantiated geocoder for this object. Make sure you have settings.DEFAULT_GEOCODER set correctly."""
0
+ return geocoding.SHORT_NAME_MAPPINGS[settings.DEFAULT_GEOCODER]
0
+
0
   @property
0
   def coords(self):
0
- """A dictionary of latitude and longitude."""
0
- return {
0
- 'latitude': self.latitude,
0
- 'longitude': self.longitude,
0
- }
0
+ if hasattr(self.result, 'coords'):
0
+ return self.result.coords
0
+ else:
0
+ return geocoding.Coordinates(float(self.latitude or 0), float(self.longitude or 0))
0
+
0
+ @property
0
+ def coords_tuple(self):
0
+ if not hasattr(self.result, 'coords'):
0
+ return (self.latitude, self.longitude)
0
+ else:
0
+ return tuple(self.result.coords)
0
+
0
+ @property
0
+ def coords_dict(self):
0
+ if not hasattr(self.result, 'coords'):
0
+ return {u'latitude': self.latitude, u'longitude': self.longitude}
0
+ else:
0
+ return {u'longitude': self.result.coords.latitude, u'longitude': self.result.coords.longitude}
0
   
0
   @property
0
   def name(self):
0
- """If it exists, returns the friendly_name, otherwise returns the query."""
0
     return self.friendly_name or self.query
0
   
0
+ # Caching
0
   @property
0
- def coords_tuple(self):
0
- """A two-tuple of latitude and longitude."""
0
- return (self.latitude, self.longitude)
0
-
0
- def __str__(self):
0
- return self.name
0
-
0
- def save(self):
0
- if not self.created:
0
- self.created = datetime.datetime.now()
0
- if not self.geocoder:
0
- self.geocoder = getattr(geopy_geocoders, settings.DEFAULT_GEOCODER)
0
- self.refresh_if_needed(save=False)
0
- super(Location, self).save()
0
-
0
- def refresh(self, save=True):
0
- """Refreshes the geo-mapping."""
0
- try:
0
- geo_keys = settings.GEOCODING_KEYS
0
- except AttributeError:
0
- geo_keys = {}
0
- if self.geocoder.__name__ in geo_keys.keys():
0
- geocoder = self.geocoder(geo_keys[self.geocoder.__name__])
0
- else:
0
- geocoder = self.geocoder()
0
- try:
0
- place, (self.latitude, self.longitude) = geocoder.geocode(self.query)
0
- self.refreshed = datetime.datetime.now()
0
- if save:
0
- self.save()
0
- except:
0
- raise geo_misc.GeocodingError, 'The location \'%s\' could not be geocoded.' % self.query
0
- return True
0
-
0
- def refresh_if_needed(self, *args, **kwargs):
0
- """Refreshes the geo-mapping if it has already expired, or we don't have any data
0
- already"""
0
- if self.expired or not (self.latitude or self.longitude):
0
- return self.refresh(*args, **kwargs)
0
- else:
0
- return False
0
+ def expires(self):
0
+ """Returns the datetime when this object will be deemed to have expired."""
0
+ return self.refreshed + relativedelta(**settings.MAX_LOCATION_CACHE_AGE)
0
   
0
   @property
0
   def expired(self):
0
- if datetime.datetime.now() > (self.created + relativedelta.relativedelta(**settings.MAX_LOCATION_CACHE_AGE)):
0
+ """Returns boolean as to whether this object has 'expired'. Always returns False if not geocoded."""
0
+ if not self.geocoded:
0
+ # This location hasn't been geocoded
0
+ return False
0
+ elif datetime.datetime.now() >= self.expires:
0
+ # The location has expired
0
+ return True
0
+ elif not (self.result and hasattr(self.result, 'coords')):
0
+ # The location hasn't yet been geocoded, but it should have been
0
       return True
0
- return False
0
+ else:
0
+ # The location hasn't expired
0
+ return False
0
+
0
+ def force_refresh(self):
0
+ """Forces a refresh of the geo-mapping by re-geocoding (if the location is geocoded)."""
0
+ if self.geocoded:
0
+ self.result = self.get_geocoder()(self).geocode()
0
+ self.latitude, self.longitude = tuple(self.result.coords)[:2]
0
+ self.refreshed = datetime.datetime.now()
0
+ return self
0
   
0
+ def refresh(self):
0
+ """Refreshes the geo-mapping it has already expired."""
0
+ if self.expired:
0
+ self.force_refresh()
0
+ return self
0
+
0
+ # Conveniences
0
   def distance_between(self, other_location, units='miles'):
0
     """Calculates the distance between this Location object and another Location object.
0
- units should be a string containing the unit of measurement (default: miles) you
0
- would like the result returned in (kilometers, miles, feet or nautical)."""
0
-
0
+ units should be a string containing the unit of measurement (default: miles) you would like
0
+ the result returned in (kilometers, miles, feet or nautical)."""
0
     if self.coords_tuple == other_location.coords_tuple:
0
       return 0
0
     dist_obj = geopy_distance.distance(self.coords_tuple, other_location.coords_tuple)
0
@@ -170,7 +173,7 @@ class Location(models.Model):
0
     """Given 2x two-tuples containing lat/long pairs (the northwest and southeast corners
0
      bounding a segment of the earth), returns Boolean as to whether this Location falls
0
      inside the area."""
0
- if (north_west[0] < self.latitude < south_east[0]) and (north_west[1] < self.longitude < south_east[1]):
0
+ if (north_west[0] > self.latitude > south_east[0]) and (north_west[1] < self.longitude < south_east[1]):
0
       return True
0
     else:
0
- return False
0
+ return False
0
\ No newline at end of file
...
1
2
3
4
 
5
6
7
8
9
10
 
11
12
13
...
23
24
25
26
 
27
28
 
29
30
31
32
33
34
35
 
36
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
39
40
41
42
 
 
 
 
 
 
 
 
43
44
45
46
47
48
49
50
51
52
 
53
54
55
56
57
58
59
 
 
 
 
 
 
 
 
 
 
 
60
...
1
2
3
 
4
5
6
7
8
9
10
11
12
13
14
...
24
25
26
 
27
28
 
29
30
31
32
33
34
35
 
36
37
 
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
 
 
 
66
67
68
69
70
71
72
73
74
75
76
 
 
 
 
 
77
 
78
79
80
81
 
 
 
 
82
83
84
85
86
87
88
89
90
91
92
93
0
@@ -1,13 +1,14 @@
0
 # -*- coding: utf-8 -*-
0
 """Unit testing for this module's fields and a subset of the model's functions.."""
0
 
0
-from geopy import geocoders as geopy_geocoders, distance as geopy_distance
0
+from geopy import distance as geopy_distance
0
 from django.test import TestCase
0
 from django.db import models
0
 from django.conf import settings
0
 from fields import PickledObjectField
0
 from test_assets import *
0
 import models as geo_models
0
+import geocoding
0
 
0
 class PickledObjectFieldTests(TestCase):
0
   def setUp(self):
0
@@ -23,37 +24,69 @@ class PickledObjectFieldTests(TestCase):
0
   def testDataIntegriry(self):
0
     """Tests that data remains the same when saved to and fetched from the database."""
0
     for value in self.testing_data:
0
- model_test = TestingModel(pickle_field=value)
0
+ model_test = PickleTestingModel(pickle_field=value)
0
       model_test.save()
0
- model_test = TestingModel.objects.get(id__exact=model_test.id)
0
+ model_test = PickleTestingModel.objects.get(id__exact=model_test.id)
0
       self.assertEquals(value, model_test.pickle_field)
0
       model_test.delete()
0
   
0
   def testLookups(self):
0
     """Tests that lookups can be performed on data once stored in the database."""
0
     for value in self.testing_data:
0
- model_test = TestingModel(pickle_field=value)
0
+ model_test = PickleTestingModel(pickle_field=value)
0
       model_test.save()
0
- self.assertEquals(value, TestingModel.objects.get(pickle_field__exact=value).pickle_field)
0
+ self.assertEquals(value, PickleTestingModel.objects.get(pickle_field__exact=value).pickle_field)
0
+
0
+class DictionaryFieldTests(TestCase):
0
+ def setUp(self):
0
+ self.valid_testing_data = (
0
+ {1:1, 2:4, 3:6, 4:8, 5:10},
0
+ {u'Hello': u'Bonjour', u'こんにちは': u'你好'}
0
+ )
0
+ self.invalid_testing_data = (
0
+ (1, 2, 3, 5, 5),
0
+ [1, 2, 3, 4, 5],
0
+ 'Hello',
0
+ 1,
0
+ 1.001,
0
+ TestCustomDataType('Hello World'),
0
+ )
0
+ return super(DictionaryFieldTests, self).setUp()
0
+
0
+ def testDataTypes(self):
0
+ """Tests the field handles different data types appropriately."""
0
+ # Test valid data types (ones that should perform fine)
0
+ for value in self.valid_testing_data:
0
+ model_test = DictTestingModel(dictionary_field=value)
0
+ model_test.save()
0
+ self.assertEquals(value, DictTestingModel.objects.get(dictionary_field__exact=value).dictionary_field)
0
+
0
 
0
 class GeocodingTest(TestCase):
0
- def setUp(self, query='London, UK'):
0
- self.query = query
0
- self.location_object = geo_models.Location.objects.create(query=self.query)
0
+ def __init__(self, *args, **kwargs):
0
+ self.query = 'London, UK'
0
+ self.location_object = geo_models.Location.objects.get_or_create(query=self.query, geocoded=True)[0]
0
+ return super(GeocodingTest, self).__init__(*args, **kwargs)
0
+
0
+ def testGeocoding(self):
0
+ correct_coords = tuple(geocoding.SHORT_NAME_MAPPINGS[settings.DEFAULT_GEOCODER](DummyLocation(self.query)).geocode().coords)
0
+ self.assertEquals(correct_coords, self.location_object.coords_tuple)
0
   
0
   def testModelFunctions(self):
0
     """Tests that the various functions of the Location model perform as expected."""
0
- # Test the co-ordinate dictionary
0
- self.assertEquals({
0
- 'latitude': self.location_object.latitude,
0
- 'longitude': self.location_object.longitude,
0
- }, self.location_object.coords)
0
     # Test the co-ordinate two-tuple
0
- self.assertEquals((self.location_object.latitude, self.location_object.longitude), self.location_object.coords_tuple)
0
+ self.assertEquals((self.location_object.latitude, self.location_object.longitude, 0.0), self.location_object.coords_tuple)
0
     # Test the name convenience function - we haven't set a friendly name so this should be equal
0
     # to the query
0
     self.assertEquals(self.query, self.location_object.query)
0
-
0
- def testGeocoding(self):
0
- returned_query, correct_coords = getattr(geopy_geocoders, settings.DEFAULT_GEOCODER)(settings.GEOCODING_KEYS[settings.DEFAULT_GEOCODER]).geocode(self.query)
0
- self.assertEquals(correct_coords, self.location_object.coords_tuple)
0
+ # Test that the object is indexable (latitude and longitude)
0
+ self.assertEquals(self.location_object[0], self.location_object.latitude)
0
+ self.assertEquals(self.location_object[1], self.location_object.longitude)
0
+ # Test the within_bounds function, with two locations known to be northwest and southeast of London
0
+ self.location_object_nw = geo_models.Location.objects.get_or_create(query='Birmingham, UK', geocoded=True)[0]
0
+ self.location_object_se = geo_models.Location.objects.get_or_create(query='Brussels, Belgium', geocoded=True)[0]
0
+ self.assertEquals(self.location_object.within_bounds(north_west=self.location_object_nw, south_east=self.location_object_se), True)
0
+ # Also test it with objects in opposite parts of the world
0
+ self.assertEquals(True, geo_models.Location.objects.get_or_create(query='Sydney, Australia', geocoded=True)[0].within_bounds(north_west=geo_models.Location.objects.get_or_create(query='Darwin, Australia', geocoded=True)[0], south_east=geo_models.Location.objects.get_or_create(query='Wellington, New Zealand', geocoded=True)[0]))
0
+ # And finally test that it fails if given an area that is is not in
0
+ self.assertEquals(False, self.location_object.within_bounds(north_west=geo_models.Location.objects.get_or_create(query='New York, NY, USA', geocoded=True)[0], south_east=self.location_object_nw))
0
\ No newline at end of file

Comments

    No one has commented yet.