From 25d646fa9a7a1cf1c62053047d65df98f1687ba0 Mon Sep 17 00:00:00 2001 From: Geoff Hing Date: Thu, 31 Jul 2014 00:19:12 -0400 Subject: [PATCH] Add model for census tract Addresses https://github.com/sc3/cook-convictions/issues/46 --- README.rst | 14 ++ .../management/commands/load_spatial_data.py | 3 +- .../migrations/0013_auto__add_censustract.py | 170 ++++++++++++++++++ convictions_data/models.py | 52 +++++- convictions_data/signals.py | 2 + 5 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 convictions_data/migrations/0013_auto__add_censustract.py diff --git a/README.rst b/README.rst index 060ebbb..080ca6b 100644 --- a/README.rst +++ b/README.rst @@ -33,6 +33,12 @@ Then run:: ./manage.py load_spatial_data Municipality data/Municipality/Municipality.shp +Download and unpack the Shapefile version of the Census Tract data. + +Then run:: + + ./manage.py load_spatial_data CensusTract data/CensusTracts2010/CensusTractsTIGER2010.shp + Load raw dispositions data ------------------------- @@ -54,3 +60,11 @@ Geocode disposition records :: ./manage.py geocode_dispositions + + +Other datasets +============== + +* `Boundaries - Community Areas (current) `_ +* `Cook County Municipalities `_ +* `Boundaries - Census Tracts - 2010 `_ diff --git a/convictions_data/management/commands/load_spatial_data.py b/convictions_data/management/commands/load_spatial_data.py index f5564a8..b105c18 100644 --- a/convictions_data/management/commands/load_spatial_data.py +++ b/convictions_data/management/commands/load_spatial_data.py @@ -2,6 +2,7 @@ from django.contrib.gis.utils import LayerMapping import convictions_data.models +from convictions_data.signals import post_load_spatial_data class Command(BaseCommand): args = " " @@ -15,5 +16,5 @@ def handle(self, *args, **options): lm = LayerMapping(model_cls, shapefile, model_cls.FIELD_MAPPING) lm.save(strict=True, verbose=True) - + post_load_spatial_data.send(sender=self, model=model_cls) diff --git a/convictions_data/migrations/0013_auto__add_censustract.py b/convictions_data/migrations/0013_auto__add_censustract.py new file mode 100644 index 0000000..3390c79 --- /dev/null +++ b/convictions_data/migrations/0013_auto__add_censustract.py @@ -0,0 +1,170 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'CensusTract' + db.create_table('convictions_data_censustract', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('statefp10', self.gf('django.db.models.fields.CharField')(max_length=2)), + ('countyfp10', self.gf('django.db.models.fields.CharField')(max_length=3)), + ('tractce10', self.gf('django.db.models.fields.CharField')(max_length=6)), + ('geoid10', self.gf('django.db.models.fields.CharField')(max_length=11, db_index=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=7, db_index=True)), + ('community_area_number', self.gf('django.db.models.fields.IntegerField')()), + ('notes', self.gf('django.db.models.fields.CharField')(max_length=80)), + ('boundary', self.gf('django.contrib.gis.db.models.fields.MultiPolygonField')()), + ('community_area', self.gf('django.db.models.fields.related.ForeignKey')(null=True, to=orm['convictions_data.CommunityArea'])), + )) + db.send_create_signal('convictions_data', ['CensusTract']) + + + def backwards(self, orm): + # Deleting model 'CensusTract' + db.delete_table('convictions_data_censustract') + + + models = { + 'convictions_data.censustract': { + 'Meta': {'object_name': 'CensusTract'}, + 'boundary': ('django.contrib.gis.db.models.fields.MultiPolygonField', [], {}), + 'community_area': ('django.db.models.fields.related.ForeignKey', [], {'null': 'True', 'to': "orm['convictions_data.CommunityArea']"}), + 'community_area_number': ('django.db.models.fields.IntegerField', [], {}), + 'countyfp10': ('django.db.models.fields.CharField', [], {'max_length': '3'}), + 'geoid10': ('django.db.models.fields.CharField', [], {'max_length': '11', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '7', 'db_index': 'True'}), + 'notes': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'statefp10': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'tractce10': ('django.db.models.fields.CharField', [], {'max_length': '6'}) + }, + 'convictions_data.communityarea': { + 'Meta': {'object_name': 'CommunityArea'}, + 'boundary': ('django.contrib.gis.db.models.fields.MultiPolygonField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '80'}), + 'number': ('django.db.models.fields.IntegerField', [], {}), + 'shape_area': ('django.db.models.fields.FloatField', [], {}), + 'shape_len': ('django.db.models.fields.FloatField', [], {}) + }, + 'convictions_data.conviction': { + 'Meta': {'object_name': 'Conviction'}, + 'case_number': ('django.db.models.fields.CharField', [], {'max_length': '200', 'db_index': 'True'}), + 'chrgdispdate': ('django.db.models.fields.DateField', [], {'null': 'True'}), + 'city': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'community_area': ('django.db.models.fields.related.ForeignKey', [], {'null': 'True', 'to': "orm['convictions_data.CommunityArea']"}), + 'county': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '80'}), + 'ctlbkngno': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'dob': ('django.db.models.fields.DateField', [], {'null': 'True'}), + 'fbiidno': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'fgrprntno': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'final_statute': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'iucr_category': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'db_index': 'True'}), + 'iucr_code': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'db_index': 'True'}), + 'sex': ('django.db.models.fields.CharField', [], {'max_length': '10', 'db_index': 'True'}), + 'st_address': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'statepoliceid': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '5'}) + }, + 'convictions_data.disposition': { + 'Meta': {'object_name': 'Disposition'}, + 'ammndchargstatute': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'ammndchrgclass': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'ammndchrgdescr': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'ammndchrgtype': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'amtoffine': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'arrest_date': ('django.db.models.fields.DateField', [], {'null': 'True'}), + 'case_number': ('django.db.models.fields.CharField', [], {'max_length': '200', 'db_index': 'True'}), + 'chrgclass': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'chrgdesc': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'chrgdisp': ('django.db.models.fields.CharField', [], {'max_length': '30'}), + 'chrgdispdate': ('django.db.models.fields.DateField', [], {'null': 'True', 'db_index': 'True'}), + 'chrgtype': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'chrgtype2': ('django.db.models.fields.CharField', [], {'max_length': '15'}), + 'city': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'community_area': ('django.db.models.fields.related.ForeignKey', [], {'null': 'True', 'to': "orm['convictions_data.CommunityArea']"}), + 'conviction': ('django.db.models.fields.related.ForeignKey', [], {'null': 'True', 'to': "orm['convictions_data.Conviction']"}), + 'county': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '80'}), + 'ctlbkngno': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'dob': ('django.db.models.fields.DateField', [], {'null': 'True'}), + 'fbiidno': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'fgrprntno': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'final_statute': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'db_index': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'initial_date': ('django.db.models.fields.DateField', [], {'null': 'True', 'db_index': 'True'}), + 'iucr_category': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '50', 'db_index': 'True'}), + 'iucr_code': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'db_index': 'True'}), + 'lat': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'lon': ('django.db.models.fields.FloatField', [], {'null': 'True'}), + 'maxsent_days': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'maxsent_death': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'maxsent_life': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'maxsent_months': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'maxsent_years': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'minsent_days': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'minsent_death': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'minsent_life': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'minsent_months': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'minsent_years': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'raw_disposition': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['convictions_data.RawDisposition']"}), + 'sequence_number': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'sex': ('django.db.models.fields.CharField', [], {'max_length': '10'}), + 'st_address': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '2'}), + 'statepoliceid': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'statute': ('django.db.models.fields.CharField', [], {'max_length': '50'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '5'}) + }, + 'convictions_data.municipality': { + 'Meta': {'object_name': 'Municipality'}, + 'agency_id': ('django.db.models.fields.IntegerField', [], {}), + 'agency_name': ('django.db.models.fields.CharField', [], {'max_length': '60'}), + 'boundary': ('django.contrib.gis.db.models.fields.MultiPolygonField', [], {}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'municipality_name': ('django.db.models.fields.CharField', [], {'max_length': '25'}), + 'sde_length': ('django.db.models.fields.FloatField', [], {}), + 'shape_area': ('django.db.models.fields.FloatField', [], {}), + 'shape_length': ('django.db.models.fields.FloatField', [], {}), + 'st_area': ('django.db.models.fields.FloatField', [], {}) + }, + 'convictions_data.rawdisposition': { + 'Meta': {'object_name': 'RawDisposition'}, + 'ammndchargstatute': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'ammndchrgclass': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'ammndchrgdescr': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'ammndchrgtype': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'amtoffine': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'arrest_date': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'case_number': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'chrgclass': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'chrgdesc': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'chrgdisp': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'chrgdispdate': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'chrgtype': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'chrgtype2': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'city_state': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'ctlbkngno': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'dob': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'fbiidno': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'fgrprntno': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'initial_date': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'maxsent': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'minsent': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'sequence_number': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'sex': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'st_address': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'statepoliceid': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'statute': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + } + } + + complete_apps = ['convictions_data'] \ No newline at end of file diff --git a/convictions_data/models.py b/convictions_data/models.py index 68866d6..d42ad17 100644 --- a/convictions_data/models.py +++ b/convictions_data/models.py @@ -14,7 +14,8 @@ from convictions_data.geocoders import BatchOpenMapQuest from convictions_data.cleaner import CityStateCleaner, CityStateSplitter from convictions_data.statute import get_iucr -from convictions_data.signals import pre_geocode_page, post_geocode_page +from convictions_data.signals import (pre_geocode_page, post_geocode_page, + post_load_spatial_data) logger = logging.getLogger(__name__) @@ -763,3 +764,52 @@ class CommunityArea(geo_models.Model): def __str__(self): return self.name + + +class CensusTractManager(geo_models.GeoManager): + def set_community_area_relations(self): + for tract in self.get_query_set().all(): + ca = CommunityArea.objects.get(number=tract.community_area_number) + # BOOKMARK + tract.community_area = ca + tract.save() + + +class CensusTract(geo_models.Model): + """ + Census Tract + + Wraps + https://data.cityofchicago.org/Facilities-Geographic-Boundaries/Boundaries-Census-Tracts-2010/5jrd-6zik + """ + statefp10 = geo_models.CharField(max_length=2) + countyfp10 = geo_models.CharField(max_length=3) + tractce10 = geo_models.CharField(max_length=6) + geoid10 = geo_models.CharField(max_length=11, db_index=True) + name = geo_models.CharField(max_length=7, db_index=True) + community_area_number = geo_models.IntegerField() + notes = geo_models.CharField(max_length=80) + + boundary = geo_models.MultiPolygonField() + + community_area = geo_models.ForeignKey(CommunityArea, null=True) + + objects = CensusTractManager() + + FIELD_MAPPING = { + 'statefp10': 'STATEFP10', + 'countyfp10': 'COUNTYFP10', + 'tractce10': 'TRACTCE10', + 'geoid10': 'GEOID10', + 'name': 'NAME10', + 'community_area_number': 'COMMAREA_N', + 'notes': 'NOTES', + 'boundary': 'MULTIPOLYGON', + } + + +def handle_post_load_spatial_data(sender, **kwargs): + if kwargs['model'] == CensusTract: + CensusTract.objects.set_community_area_relations() + +post_load_spatial_data.connect(handle_post_load_spatial_data) diff --git a/convictions_data/signals.py b/convictions_data/signals.py index 8346abc..3bc669b 100644 --- a/convictions_data/signals.py +++ b/convictions_data/signals.py @@ -4,4 +4,6 @@ post_geocode_page = django.dispatch.Signal(providing_args=["page_number", "num_pages"]) +post_load_spatial_data = django.dispatch.Signal(providing_args=["model"]) +