diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac5a382 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +build + diff --git a/README.rst b/README.rst index ba54074..16e57e8 100644 --- a/README.rst +++ b/README.rst @@ -15,9 +15,14 @@ To follow development, be sure to join the `Google Group`_. ``armstrong.apps.places`` is part of the `Armstrong`_ project. You're probably looking for that. +Contributions +------------- +August 2012 - Place model contributed by `Paul Bailey`_ from `Mouth Watering Media`_ .. _Armstrong: http://www.armstrongcms.org/ .. _Bay Citizen: http://www.baycitizen.org/ .. _John S. and James L. Knight Foundation: http://www.knightfoundation.org/ .. _Texas Tribune: http://www.texastribune.org/ .. _Google Group: http://groups.google.com/group/armstrongcms +.. _Paul Bailey: https://plus.google.com/u/0/111994399408696258069/about +.. _Mouth Watering Media: http://mouthwateringmedia.com/ diff --git a/armstrong/apps/places/admin.py b/armstrong/apps/places/admin.py new file mode 100644 index 0000000..d065015 --- /dev/null +++ b/armstrong/apps/places/admin.py @@ -0,0 +1,24 @@ +from django.contrib import admin +from django.utils.translation import ugettext as _ + +from armstrong.core.arm_content.admin import fieldsets +from armstrong import hatband + +from .models import Place + +class PlaceAdmin (admin.ModelAdmin): + fieldsets = ( + (None, { + 'fields': ('title', 'slug', 'summary'), + }), + + (_('Location'), { + 'fields': ('address1', 'address2', ('city', 'state'), ('zipcode', 'country'), 'coordinate'), + }), + + fieldsets.TAXONOMY, + fieldsets.PUBLICATION, + fieldsets.AUTHORS, + ) + +hatband.site.register(Place, PlaceAdmin) diff --git a/armstrong/apps/places/migrations/0001_initial.py b/armstrong/apps/places/migrations/0001_initial.py new file mode 100644 index 0000000..e9ceee6 --- /dev/null +++ b/armstrong/apps/places/migrations/0001_initial.py @@ -0,0 +1,129 @@ +# -*- coding: utf-8 -*- +import 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 'Place' + db.create_table('places_place', ( + ('content_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['content.Content'], unique=True, primary_key=True)), + ('address1', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)), + ('address2', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)), + ('zipcode', self.gf('django.db.models.fields.CharField')(max_length=30, null=True, blank=True)), + ('city', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)), + ('state', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)), + ('country', self.gf('django.db.models.fields.CharField')(max_length=100, null=True, blank=True)), + ('coordinate', self.gf('django.contrib.gis.db.models.fields.PointField')()), + )) + db.send_create_signal('places', ['Place']) + + def backwards(self, orm): + # Deleting model 'Place' + db.delete_table('places_place') + + models = { + 'arm_access.accessobject': { + 'Meta': {'object_name': 'AccessObject'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}) + }, + 'arm_sections.section': { + 'Meta': {'object_name': 'Section'}, + 'full_slug': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'parent': ('mptt.fields.TreeForeignKey', [], {'to': "orm['arm_sections.Section']", 'null': 'True', 'blank': 'True'}), + 'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'summary': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}), + 'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}) + }, + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'content.content': { + 'Meta': {'object_name': 'Content'}, + 'access': ('armstrong.core.arm_access.fields.AccessField', [], {}), + 'authors': ('armstrong.core.arm_content.fields.authors.AuthorsField', [], {'to': "orm['auth.User']", 'override_field_name': "'authors_override'", 'symmetrical': 'False', 'extra_field_name': "'authors_extra'", 'blank': 'True'}), + 'authors_extra': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'authors_override': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'pub_date': ('django.db.models.fields.DateTimeField', [], {'db_index': 'True'}), + 'pub_status': ('django.db.models.fields.CharField', [], {'max_length': '1'}), + 'sections': ('django.db.models.fields.related.ManyToManyField', [], {'blank': 'True', 'related_name': "'content_content_alternates'", 'null': 'True', 'symmetrical': 'False', 'to': "orm['arm_sections.Section']"}), + 'sites': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['sites.Site']", 'symmetrical': 'False'}), + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50'}), + 'summary': ('django.db.models.fields.TextField', [], {}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'places.place': { + 'Meta': {'object_name': 'Place', '_ormbases': ['content.Content']}, + 'address1': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'address2': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'city': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'content_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['content.Content']", 'unique': 'True', 'primary_key': 'True'}), + 'coordinate': ('django.contrib.gis.db.models.fields.PointField', [], {}), + 'country': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'state': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'zipcode': ('django.db.models.fields.CharField', [], {'max_length': '30', 'null': 'True', 'blank': 'True'}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'taggit.tag': { + 'Meta': {'object_name': 'Tag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'}) + }, + 'taggit.taggeditem': { + 'Meta': {'object_name': 'TaggedItem'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"}) + } + } + + complete_apps = ['places'] \ No newline at end of file diff --git a/armstrong/apps/places/migrations/__init__.py b/armstrong/apps/places/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/armstrong/apps/places/models.py b/armstrong/apps/places/models.py new file mode 100644 index 0000000..56eebea --- /dev/null +++ b/armstrong/apps/places/models.py @@ -0,0 +1,17 @@ +from django.contrib.gis.db import models +from django.utils.translation import ugettext as _ + +from armstrong.apps.content.models import Content + +class Place (Content): + address1 = models.CharField(_('Address 1'), max_length=100, blank=True, null=True) + address2 = models.CharField(_('Address 2'), max_length=100, blank=True, null=True) + zipcode = models.CharField(_('Zip code'), max_length=30, blank=True, null=True) + city = models.CharField(max_length=100, blank=True, null=True) + state = models.CharField(_('State/Province'), max_length=100, blank=True, null=True) + country = models.CharField(max_length=100, blank=True, null=True) + + coordinate = models.PointField() + + objects = models.GeoManager() + \ No newline at end of file diff --git a/armstrong/apps/places/tests.py b/armstrong/apps/places/tests.py new file mode 100644 index 0000000..276221d --- /dev/null +++ b/armstrong/apps/places/tests.py @@ -0,0 +1,51 @@ +import datetime + +from django.test import TestCase +from django.core.urlresolvers import reverse, resolve + +from django.contrib.gis.geos import Point +from django.contrib.gis.measure import D + +from .models import Place + +class PlacesTestCase (TestCase): + def setUp(self): + self.home = Place( + address1 = '1206 Halls Bridge', + address2 = None, + zipcode = '77573', + city = 'League City', + state = 'TX', + country = 'US', + coordinate = Point(-95.087372, 29.516589), + + pub_date = datetime.datetime.now() + ) + self.home.save() + + self.work = Place( + address1 = '3657 Briarpark Drive', + address2 = 'Suite 101', + zipcode = '77042', + city = 'Houston', + state = 'TX', + country = 'US', + coordinate = Point(-95.54835, 29.72546), + + pub_date = datetime.datetime.now() + ) + self.work.save() + + def tearDown(self): + self.home.delete() + self.work.delete() + + def test_model (self): + bay_brook_mall = Point(-95.14820, 29.54211) + qs = Place.objects.filter(coordinate__distance_lte=(bay_brook_mall, D(mi=5))) + self.assertEqual(qs.count(), 1) + self.assertEqual(qs[0].id, self.home.id) + + qs = Place.objects.filter(coordinate__distance_lte=(bay_brook_mall, D(mi=30))) + self.assertEqual(qs.count(), 2) + \ No newline at end of file