Skip to content
Browse files

Initial commit. Currently functional, requires a bit of a hack to

work at the moment as a result of a bug in inheriting a ForeignKey
model field.
  • Loading branch information...
0 parents commit 570856d62694b1ea07b8b86bf0397ae43786d5ab @furious-luke committed Apr 17, 2011
Showing with 395 additions and 0 deletions.
  1. +21 −0 README
  2. 0 address/__init__.py
  3. +183 −0 address/models.py
  4. +190 −0 address/tests.py
  5. +1 −0 address/views.py
21 README
@@ -0,0 +1,21 @@
+==============
+django-address
+==============
+--------------------
+Simplified addresses
+--------------------
+
+The Model
+=========
+
+TODO
+
+Address Field
+=============
+
+TODO
+
+Usage
+=====
+
+TODO
0 address/__init__.py
No changes.
183 address/models.py
@@ -0,0 +1,183 @@
+from django.db import models
+from django.core.exceptions import ValidationError
+
+
+class Country(models.Model):
+ name = models.CharField(max_length=40, unique=True)
+ code = models.CharField(max_length=2, unique=True, primary_key=True)
+
+ class Meta:
+ verbose_name_plural = 'Countries'
+ ordering = ('name',)
+
+ def __unicode__(self):
+ return u'%s'%self.name
+
+
+class State(models.Model):
+ name = models.CharField(max_length=165, blank=True)
+ code = models.CharField(max_length=3, blank=True)
+ country = models.ForeignKey(Country, related_name='states')
+
+ class Meta:
+ unique_together = ('name', 'country')
+ ordering = ('country', 'name')
+
+ def __unicode__(self):
+ txt = ''
+ if self.name:
+ txt += u'%s, '%self.name
+ txt += unicode(self.country)
+ return txt
+
+
+class Locality(models.Model):
+ name = models.CharField(max_length=165, blank=True)
+ postal_code = models.CharField(max_length=10, blank=True)
+ state = models.ForeignKey(State, related_name='localities')
+
+ class Meta:
+ verbose_name_plural = 'Localities'
+ unique_together = ('name', 'state')
+ ordering = ('state', 'name')
+
+ def __unicode__(self):
+ txt = ''
+ if self.name:
+ txt = u'%s, '%self.name
+ if self.postal_code:
+ txt += u'%s, '%self.postal_code
+ txt += unicode(self.state)
+ return txt
+
+
+class Address(models.Model):
+ street_address = models.CharField(max_length=100, blank=True)
+ locality = models.ForeignKey(Locality, related_name='addresses')
+
+ class Meta:
+ verbose_name_plural = 'Addresses'
+ unique_together = ('street_address', 'locality')
+ ordering = ('locality', 'street_address')
+
+ def __unicode__(self):
+ txt = ''
+ if self.street_address:
+ txt += u'%s, '%self.street_address
+ txt += unicode(self.locality)
+ return txt
+
+
+class AddressField(models.ForeignKey):
+ # __metaclass__ = models.SubfieldBase
+ description = 'An address'
+
+ def __init__(self, **kwargs):
+ super(AddressField, self).__init__(Address, **kwargs)
+
+ # def to_python(self, value):
+
+ # # A dictionary of named address components.
+ # if isinstance(value, dict):
+ # country = value.get('country', '')
+ # country_code = value.get('country_code', '')
+ # state = value.get('state', '')
+ # state_code = value.get('state_code', '')
+ # locality = value.get('locality', '')
+ # postal_code = value.get('postal_code', '')
+ # street_address = value.get('street_address', '')
+
+ # # Handle the country.
+ # if not country:
+ # raise TypeError('Must have a country name.')
+ # try:
+ # country_obj = Country.objects.get(name=country)
+ # except Country.DoesNotExist:
+ # country_obj = Country(name=country, code=country_code)
+
+ # # Handle the state.
+ # try:
+ # state_obj = State.objects.get(name=state, country=country_obj)
+ # except State.DoesNotExist:
+ # state_obj = State(name=state, code=state_code, country=country_obj)
+
+ # # Handle the locality.
+ # try:
+ # locality_obj = Locality.objects.get(name=locality, state=state_obj)
+ # except Locality.DoesNotExist:
+ # locality_obj = Locality(name=locality, postal_code=postal_code, state=state_obj)
+
+ # # Handle the address.
+ # try:
+ # address_obj = Address.objects.get(street_address=street_address, locality=locality_obj)
+ # except Address.DoesNotExist:
+ # address_obj = Address(street_address=street_address, locality=locality_obj)
+
+ # # Done.
+ # return address_obj
+
+ # # Is it already an address object?
+ # elif isinstance(value, Address):
+ # return value
+
+ # # Try to deserialise a string ... how?
+ # raise ValidationError('Invalid locality value')
+
+ def pre_save(self, model_instance, add):
+ address = getattr(model_instance, self.name)
+ address.locality.state.country.save()
+ address.locality.state.save()
+ address.locality.state_id = address.locality.state.pk
+ address.locality.save()
+ address.locality_id = address.locality.pk
+ address.save()
+ return address.pk
+
+
+def address_hack(value):
+
+ # A dictionary of named address components.
+ if isinstance(value, dict):
+ country = value.get('country', '')
+ country_code = value.get('country_code', '')
+ state = value.get('state', '')
+ state_code = value.get('state_code', '')
+ locality = value.get('locality', '')
+ postal_code = value.get('postal_code', '')
+ street_address = value.get('street_address', '')
+
+ # Handle the country.
+ if not country:
+ raise TypeError('Must have a country name.')
+ try:
+ country_obj = Country.objects.get(name=country)
+ except Country.DoesNotExist:
+ country_obj = Country(name=country, code=country_code)
+
+ # Handle the state.
+ try:
+ state_obj = State.objects.get(name=state, country=country_obj)
+ except State.DoesNotExist:
+ state_obj = State(name=state, code=state_code, country=country_obj)
+
+ # Handle the locality.
+ try:
+ locality_obj = Locality.objects.get(name=locality, state=state_obj)
+ except Locality.DoesNotExist:
+ locality_obj = Locality(name=locality, postal_code=postal_code, state=state_obj)
+
+ # Handle the address.
+ try:
+ address_obj = Address.objects.get(street_address=street_address, locality=locality_obj)
+ except Address.DoesNotExist:
+ address_obj = Address(street_address=street_address, locality=locality_obj)
+
+ # Done.
+ return address_obj
+
+ # Is it already an address object?
+ elif isinstance(value, Address):
+ return value
+
+ # Try to deserialise a string ... how?
+ raise ValidationError('Invalid locality value')
190 address/tests.py
@@ -0,0 +1,190 @@
+from django.test import TestCase
+from django.db import IntegrityError
+from django.db.models import Model
+import models
+
+
+class CountryTestCase(TestCase):
+
+ def setUp(self):
+ self.au = models.Country.objects.create(name='Australia', code='AU')
+ self.nz = models.Country.objects.create(name='New Zealand', code='NZ')
+ self.be = models.Country.objects.create(name='Belgium', code='BE')
+
+ def test_required_name(self):
+ self.assertRaises(IntegrityError, models.Country.objects.create, code='BL')
+
+ def test_required_code(self):
+ self.assertRaises(IntegrityError, models.Country.objects.create, name='Blah')
+
+ def test_ordering(self):
+ qs = models.Country.objects.all()
+ self.assertEqual(qs.count(), 3)
+ self.assertEqual(qs[0].code, 'AU')
+ self.assertEqual(qs[1].code, 'BE')
+ self.assertEqual(qs[2].code, 'NZ')
+
+ def test_unique_name(self):
+ self.assertRaises(IntegrityError, models.Country.objects.create, name='Australia', code='**')
+
+ def test_unicode(self):
+ self.assertEqual(unicode(self.au), u'Australia')
+
+
+class StateTestCase(TestCase):
+
+ def setUp(self):
+ self.au = models.Country.objects.create(name='Australia', code='AU')
+ self.vic = models.State.objects.create(name='Victoria', code='VIC', country=self.au)
+ self.tas = models.State.objects.create(name='Tasmania', code='TAS', country=self.au)
+ self.qld = models.State.objects.create(name='Queensland', country=self.au)
+ self.empty = models.State.objects.create(country=self.au)
+ self.uk = models.Country.objects.create(name='United Kingdom', code='UK')
+ self.uk_vic = models.State.objects.create(name='Victoria', code='VIC', country=self.uk)
+
+ def test_required_country(self):
+ self.assertRaises(IntegrityError, models.State.objects.create)
+
+ def test_ordering(self):
+ qs = models.State.objects.all()
+ self.assertEqual(qs.count(), 5)
+ self.assertEqual(qs[0].name, '')
+ self.assertEqual(qs[1].name, 'Queensland')
+ self.assertEqual(qs[2].name, 'Tasmania')
+ self.assertEqual(qs[3].name, 'Victoria')
+ self.assertEqual(qs[4].name, 'Victoria')
+
+ def test_unique_name_country(self):
+ models.State.objects.create(name='Tasmania', country=self.uk)
+ self.assertRaises(IntegrityError, models.State.objects.create, name='Tasmania', country=self.au)
+
+ def test_unicode(self):
+ self.assertEqual(unicode(self.vic), u'Victoria, Australia')
+ self.assertEqual(unicode(self.empty), u'Australia')
+
+
+class LocalityTestCase(TestCase):
+
+ def setUp(self):
+ self.au = models.Country.objects.create(name='Australia', code='AU')
+ self.uk = models.Country.objects.create(name='United Kingdom', code='UK')
+
+ self.au_vic = models.State.objects.create(name='Victoria', code='VIC', country=self.au)
+ self.au_tas = models.State.objects.create(name='Tasmania', code='TAS', country=self.au)
+ self.au_qld = models.State.objects.create(name='Queensland', country=self.au)
+ self.au_empty = models.State.objects.create(country=self.au)
+ self.uk_vic = models.State.objects.create(name='Victoria', code='VIC', country=self.uk)
+
+ self.au_vic_nco = models.Locality.objects.create(name='Northcote', postal_code='3070', state=self.au_vic)
+ self.au_vic_mel = models.Locality.objects.create(name='Melbourne', postal_code='3000', state=self.au_vic)
+ self.au_vic_ftz = models.Locality.objects.create(name='Fitzroy', state=self.au_vic)
+ self.au_vic_empty = models.Locality.objects.create(state=self.au_vic)
+ self.uk_vic_mel = models.Locality.objects.create(name='Melbourne', postal_code='3000', state=self.uk_vic)
+
+ def test_required_state(self):
+ self.assertRaises(IntegrityError, models.Locality.objects.create)
+
+ def test_ordering(self):
+ qs = models.Locality.objects.all()
+ self.assertEqual(qs.count(), 5)
+ self.assertEqual(qs[0].name, '')
+ self.assertEqual(qs[1].name, 'Fitzroy')
+ self.assertEqual(qs[2].name, 'Melbourne')
+ self.assertEqual(qs[3].name, 'Northcote')
+ self.assertEqual(qs[4].name, 'Melbourne')
+
+ def test_unique_name_state(self):
+ models.Locality.objects.create(name='Melbourne', state=self.au_qld)
+ self.assertRaises(IntegrityError, models.Locality.objects.create, name='Melbourne', state=self.au_vic)
+
+ def test_unicode(self):
+ self.assertEqual(unicode(self.au_vic_mel), u'Melbourne, 3000, Victoria, Australia')
+ self.assertEqual(unicode(self.au_vic_ftz), u'Fitzroy, Victoria, Australia')
+ self.assertEqual(unicode(self.au_vic_empty), u'Victoria, Australia')
+
+
+class AddressTestCase(TestCase):
+
+ def setUp(self):
+ self.au = models.Country.objects.create(name='Australia', code='AU')
+ self.uk = models.Country.objects.create(name='United Kingdom', code='UK')
+
+ self.au_vic = models.State.objects.create(name='Victoria', code='VIC', country=self.au)
+ self.au_tas = models.State.objects.create(name='Tasmania', code='TAS', country=self.au)
+ self.au_qld = models.State.objects.create(name='Queensland', country=self.au)
+ self.au_empty = models.State.objects.create(country=self.au)
+ self.uk_vic = models.State.objects.create(name='Victoria', code='VIC', country=self.uk)
+
+ self.au_vic_nco = models.Locality.objects.create(name='Northcote', postal_code='3070', state=self.au_vic)
+ self.au_vic_mel = models.Locality.objects.create(name='Melbourne', postal_code='3000', state=self.au_vic)
+ self.au_vic_ftz = models.Locality.objects.create(name='Fitzroy', state=self.au_vic)
+ self.au_vic_empty = models.Locality.objects.create(state=self.au_vic)
+ self.uk_vic_mel = models.Locality.objects.create(name='Melbourne', postal_code='3000', state=self.uk_vic)
+
+ self.ad1 = models.Address.objects.create(street_address='1 Some Street', locality=self.au_vic_mel)
+ self.ad2 = models.Address.objects.create(street_address='10 Other Street', locality=self.au_vic_mel)
+ self.ad3 = models.Address.objects.create(street_address='1 Some Street', locality=self.au_vic_nco)
+ self.ad_empty = models.Address.objects.create(locality=self.au_vic_nco)
+
+ def test_required_locality(self):
+ self.assertRaises(IntegrityError, models.Address.objects.create)
+
+ def test_ordering(self):
+ qs = models.Address.objects.all()
+ self.assertEqual(qs.count(), 4)
+ self.assertEqual(qs[0].street_address, '1 Some Street')
+ self.assertEqual(qs[1].street_address, '10 Other Street')
+ self.assertEqual(qs[2].street_address, '')
+ self.assertEqual(qs[3].street_address, '1 Some Street')
+
+
+ def test_unique_street_address_locality(self):
+ models.Address.objects.create(street_address='10 Other Street', locality=self.au_vic_nco)
+ self.assertRaises(
+ IntegrityError, models.Address.objects.create,
+ street_address='10 Other Street', locality=self.au_vic_mel
+ )
+
+ def test_unicode(self):
+ self.assertEqual(unicode(self.ad1), u'1 Some Street, Melbourne, 3000, Victoria, Australia')
+ self.assertEqual(unicode(self.ad_empty), u'Northcote, 3070, Victoria, Australia')
+
+
+class AddressFieldTestCase(TestCase):
+
+ class TestModel(Model):
+ address = models.AddressField()
+
+ def setUp(self):
+ self.ad1_dict = {
+ 'street_address': '1 Somewhere Street',
+ 'locality': 'Northcote',
+ 'postal_code': '3070',
+ 'state': 'Victoria',
+ 'state_code': 'VIC',
+ 'country': 'Australia',
+ 'country_code': 'AU'
+ }
+ self.test = self.TestModel()
+
+ def test_assignment(self):
+ self.test.address = models.address_hack(self.ad1_dict)
+ self.assertEqual(self.test.address.street_address, self.ad1_dict['street_address'])
+ self.assertEqual(self.test.address.locality.name, self.ad1_dict['locality'])
+ self.assertEqual(self.test.address.locality.postal_code, self.ad1_dict['postal_code'])
+ self.assertEqual(self.test.address.locality.state.name, self.ad1_dict['state'])
+ self.assertEqual(self.test.address.locality.state.code, self.ad1_dict['state_code'])
+ self.assertEqual(self.test.address.locality.state.country.name, self.ad1_dict['country'])
+ self.assertEqual(self.test.address.locality.state.country.code, self.ad1_dict['country_code'])
+
+ def test_save(self):
+ self.test.address = models.address_hack(self.ad1_dict)
+ self.test.save()
+ test = self.TestModel.objects.all()[0]
+ self.assertEqual(test.address.street_address, self.ad1_dict['street_address'])
+ self.assertEqual(test.address.locality.name, self.ad1_dict['locality'])
+ self.assertEqual(test.address.locality.postal_code, self.ad1_dict['postal_code'])
+ self.assertEqual(test.address.locality.state.name, self.ad1_dict['state'])
+ self.assertEqual(test.address.locality.state.code, self.ad1_dict['state_code'])
+ self.assertEqual(test.address.locality.state.country.name, self.ad1_dict['country'])
+ self.assertEqual(test.address.locality.state.country.code, self.ad1_dict['country_code'])
1 address/views.py
@@ -0,0 +1 @@
+# Create your views here.

0 comments on commit 570856d

Please sign in to comment.
Something went wrong with that request. Please try again.