Permalink
Browse files

[soc2009/admin-ui] Merging trunk r10924 into my branch.

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2009/admin-ui@10925 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent 6275888 commit 82b25800cdb8be78e8cfc95cca41e01a418ecc9c @zain zain committed Jun 5, 2009
Binary file not shown.
@@ -35,7 +35,7 @@ def add(self, data, connector):
return super(WhereNode, self).add(data, connector)
obj, lookup_type, value = data
- alias, col, field = obj.alias, obj.col, obj.field
+ col, field = obj.col, obj.field
if not hasattr(field, "geom_type"):
# Not a geographic field, so call `WhereNode.add`.
@@ -76,7 +76,7 @@ def add(self, data, connector):
# the `get_geo_where_clause` to construct the appropriate
# spatial SQL when `make_atom` is called.
annotation = GeoAnnotation(field, value, where)
- return super(WhereNode, self).add(((alias, col, field.db_type()), lookup_type, annotation, params), connector)
+ return super(WhereNode, self).add(((obj.alias, col, field.db_type()), lookup_type, annotation, params), connector)
def make_atom(self, child, qn):
obj, lookup_type, value_annot, params = child
@@ -143,7 +143,7 @@ def xhtml(self):
@property
def icons(self):
"Returns a sequence of GIcon objects in this map."
- return [marker.icon for marker in self.markers if marker.icon]
+ return set([marker.icon for marker in self.markers if marker.icon])
class GoogleMapSet(GoogleMap):
@@ -221,6 +221,6 @@ def onload(self):
@property
def icons(self):
"Returns a sequence of all icons in each map of the set."
- icons = []
- for map in self.maps: icons.extend(map.icons)
+ icons = set()
+ for map in self.maps: icons |= map.icons
return icons
@@ -231,6 +231,14 @@ def __init__(self, varname, image=None, iconsize=None,
self.iconanchor = iconanchor
self.infowindowanchor = infowindowanchor
+ def __cmp__(self, other):
+ return cmp(self.varname, other.varname)
+
+ def __hash__(self):
+ # XOR with hash of GIcon type so that hash('varname') won't
+ # equal hash(GIcon('varname')).
+ return hash(self.__class__) ^ hash(self.varname)
+
class GMarker(GOverlayBase):
"""
A Python wrapper for the Google GMarker object. For more information
@@ -32,3 +32,13 @@ class Parcel(models.Model):
border2 = models.PolygonField(srid=2276)
objects = models.GeoManager()
def __unicode__(self): return self.name
+
+# These use the GeoManager but do not have any geographic fields.
+class Author(models.Model):
+ name = models.CharField(max_length=100)
+ objects = models.GeoManager()
+
+class Book(models.Model):
+ title = models.CharField(max_length=100)
+ author = models.ForeignKey(Author, related_name='books')
+ objects = models.GeoManager()
@@ -1,10 +1,10 @@
import os, unittest
from django.contrib.gis.geos import *
from django.contrib.gis.db.backend import SpatialBackend
-from django.contrib.gis.db.models import F, Extent, Union
+from django.contrib.gis.db.models import Count, Extent, F, Union
from django.contrib.gis.tests.utils import no_mysql, no_oracle, no_spatialite
from django.conf import settings
-from models import City, Location, DirectoryEntry, Parcel
+from models import City, Location, DirectoryEntry, Parcel, Book, Author
cities = (('Aurora', 'TX', -97.516111, 33.058333),
('Roswell', 'NM', -104.528056, 33.387222),
@@ -196,8 +196,8 @@ def test09_pk_relations(self):
# ID values do not match their City ID values.
loc1 = Location.objects.create(point='POINT (-95.363151 29.763374)')
loc2 = Location.objects.create(point='POINT (-96.801611 32.782057)')
- dallas = City.objects.create(name='Dallas', location=loc2)
- houston = City.objects.create(name='Houston', location=loc1)
+ dallas = City.objects.create(name='Dallas', state='TX', location=loc2)
+ houston = City.objects.create(name='Houston', state='TX', location=loc1)
# The expected ID values -- notice the last two location IDs
# are out of order. We want to make sure that the related
@@ -231,6 +231,32 @@ def test11_geoquery_pickle(self):
q = pickle.loads(q_str)
self.assertEqual(GeoQuery, q.__class__)
+ def test12_count(self):
+ "Testing `Count` aggregate use with the `GeoManager`. See #11087."
+ # Creating a new City, 'Fort Worth', that uses the same location
+ # as Dallas.
+ dallas = City.objects.get(name='Dallas')
+ ftworth = City.objects.create(name='Fort Worth', state='TX', location=dallas.location)
+
+ # Count annotation should be 2 for the Dallas location now.
+ loc = Location.objects.annotate(num_cities=Count('city')).get(id=dallas.location.id)
+ self.assertEqual(2, loc.num_cities)
+
+ # Creating some data for the Book/Author non-geo models that
+ # use GeoManager. See #11087.
+ tp = Author.objects.create(name='Trevor Paglen')
+ Book.objects.create(title='Torture Taxi', author=tp)
+ Book.objects.create(title='I Could Tell You But Then You Would Have to be Destroyed by Me', author=tp)
+ Book.objects.create(title='Blank Spots on the Map', author=tp)
+ wp = Author.objects.create(name='William Patry')
+ Book.objects.create(title='Patry on Copyright', author=wp)
+
+ # Should only be one author (Trevor Paglen) returned by this query, and
+ # the annotation should have 3 for the number of books.
+ qs = Author.objects.annotate(num_books=Count('books')).filter(num_books__gt=1)
+ self.assertEqual(1, len(qs))
+ self.assertEqual(3, qs[0].num_books)
+
# TODO: Related tests for KML, GML, and distance lookups.
def suite():
@@ -12,12 +12,12 @@
def mapping(data_source, geom_name='geom', layer_key=0, multi_geom=False):
"""
- Given a DataSource, generates a dictionary that may be used
+ Given a DataSource, generates a dictionary that may be used
for invoking the LayerMapping utility.
Keyword Arguments:
`geom_name` => The name of the geometry field to use for the model.
-
+
`layer_key` => The key for specifying which layer in the DataSource to use;
defaults to 0 (the first layer). May be an integer index or a string
identifier for the layer.
@@ -31,7 +31,7 @@ def mapping(data_source, geom_name='geom', layer_key=0, multi_geom=False):
pass
else:
raise TypeError('Data source parameter must be a string or a DataSource object.')
-
+
# Creating the dictionary.
_mapping = {}
@@ -52,32 +52,32 @@ def ogrinspect(*args, **kwargs):
model name this function will generate a GeoDjango model.
Usage:
-
+
>>> from django.contrib.gis.utils import ogrinspect
>>> ogrinspect('/path/to/shapefile.shp','NewModel')
-
+
...will print model definition to stout
-
+
or put this in a python script and use to redirect the output to a new
model like:
-
+
$ python generate_model.py > myapp/models.py
-
- # generate_model.py
+
+ # generate_model.py
from django.contrib.gis.utils import ogrinspect
shp_file = 'data/mapping_hacks/world_borders.shp'
model_name = 'WorldBorders'
print ogrinspect(shp_file, model_name, multi_geom=True, srid=4326,
geom_name='shapes', blank=True)
-
+
Required Arguments
`datasource` => string or DataSource object to file pointer
-
+
`model name` => string of name of new model class to create
-
+
Optional Keyword Arguments
- `geom_name` => For specifying the model name for the Geometry Field.
+ `geom_name` => For specifying the model name for the Geometry Field.
Otherwise will default to `geom`
`layer_key` => The key for specifying which layer in the DataSource to use;
@@ -86,38 +86,38 @@ def ogrinspect(*args, **kwargs):
`srid` => The SRID to use for the Geometry Field. If it can be determined,
the SRID of the datasource is used.
-
+
`multi_geom` => Boolean (default: False) - specify as multigeometry.
-
+
`name_field` => String - specifies a field name to return for the
`__unicode__` function (which will be generated if specified).
-
- `imports` => Boolean (default: True) - set to False to omit the
- `from django.contrib.gis.db import models` code from the
+
+ `imports` => Boolean (default: True) - set to False to omit the
+ `from django.contrib.gis.db import models` code from the
autogenerated models thus avoiding duplicated imports when building
more than one model by batching ogrinspect()
-
+
`decimal` => Boolean or sequence (default: False). When set to True
all generated model fields corresponding to the `OFTReal` type will
be `DecimalField` instead of `FloatField`. A sequence of specific
field names to generate as `DecimalField` may also be used.
`blank` => Boolean or sequence (default: False). When set to True all
- generated model fields will have `blank=True`. If the user wants to
+ generated model fields will have `blank=True`. If the user wants to
give specific fields to have blank, then a list/tuple of OGR field
names may be used.
`null` => Boolean (default: False) - When set to True all generated
model fields will have `null=True`. If the user wants to specify
give specific fields to have null, then a list/tuple of OGR field
names may be used.
-
+
Note: This routine calls the _ogrinspect() helper to do the heavy lifting.
"""
return '\n'.join(s for s in _ogrinspect(*args, **kwargs))
def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=None,
- multi_geom=False, name_field=None, imports=True,
+ multi_geom=False, name_field=None, imports=True,
decimal=False, blank=False, null=False):
"""
Helper routine for `ogrinspect` that generates GeoDjango models corresponding
@@ -140,7 +140,7 @@ def _ogrinspect(data_source, model_name, geom_name='geom', layer_key=0, srid=Non
# keyword arguments.
def process_kwarg(kwarg):
if isinstance(kwarg, (list, tuple)):
- return [s.lower() for s in kwarg]
+ return [s.lower() for s in kwarg]
elif kwarg:
return [s.lower() for s in ogr_fields]
else:
@@ -164,18 +164,18 @@ def get_kwargs_str(field_name):
yield ''
yield 'class %s(models.Model):' % model_name
-
+
for field_name, width, precision, field_type in izip(ogr_fields, layer.field_widths, layer.field_precisions, layer.field_types):
# The model field name.
mfield = field_name.lower()
if mfield[-1:] == '_': mfield += 'field'
-
+
# Getting the keyword args string.
kwargs_str = get_kwargs_str(field_name)
if field_type is OFTReal:
# By default OFTReals are mapped to `FloatField`, however, they
- # may also be mapped to `DecimalField` if specified in the
+ # may also be mapped to `DecimalField` if specified in the
# `decimal` keyword.
if field_name.lower() in decimal_fields:
yield ' %s = models.DecimalField(max_digits=%d, decimal_places=%d%s)' % (mfield, width, precision, kwargs_str)
@@ -192,8 +192,8 @@ def get_kwargs_str(field_name):
elif field_type is OFTDate:
yield ' %s = models.TimeField(%s)' % (mfield, kwargs_str[2:])
else:
- raise TypeError('Unknown field type %s in %s' % (fld_type, mfield))
-
+ raise TypeError('Unknown field type %s in %s' % (field_type, mfield))
+
# TODO: Autodetection of multigeometry types (see #7218).
gtype = layer.geom_type
if multi_geom and gtype.num in (1, 2, 3):
Oops, something went wrong. Retry.

0 comments on commit 82b2580

Please sign in to comment.