-
-
Notifications
You must be signed in to change notification settings - Fork 179
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 570856d
Showing
5 changed files
with
395 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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']) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# Create your views here. |