Skip to content

Commit

Permalink
Initial commit. Currently functional, requires a bit of a hack to
Browse files Browse the repository at this point in the history
work at the moment as a result of a bug in inheriting a ForeignKey
model field.
  • Loading branch information
furious-luke committed Apr 16, 2011
0 parents commit 570856d
Show file tree
Hide file tree
Showing 5 changed files with 395 additions and 0 deletions.
21 changes: 21 additions & 0 deletions README
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
==============
django-address
==============
--------------------
Simplified addresses
--------------------

The Model
=========

TODO

Address Field
=============

TODO

Usage
=====

TODO
Empty file added address/__init__.py
Empty file.
183 changes: 183 additions & 0 deletions address/models.py
Original file line number Diff line number Diff line change
@@ -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 changes: 190 additions & 0 deletions address/tests.py
Original file line number Diff line number Diff line change
@@ -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 change: 1 addition & 0 deletions address/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Create your views here.

0 comments on commit 570856d

Please sign in to comment.