diff options
author | Rob Austein <sra@hactrn.net> | 2015-10-27 03:38:51 +0000 |
---|---|---|
committer | Rob Austein <sra@hactrn.net> | 2015-10-27 03:38:51 +0000 |
commit | 5e2f332808a680104d94afb5812e47cbc6dfcc1f (patch) | |
tree | 137c5b722096a119f761f2f10fcbf5bb013356ab /rpki | |
parent | f5efdeb3495f0de7c82c7d1139fe136e4bc05db4 (diff) |
Reimplement rpki.gui.models.IPAddressField as a subclass of CharField
for portability. With this change, the GUI appears to work with SQLite3.
svn path=/branches/tk705/; revision=6155
Diffstat (limited to 'rpki')
-rw-r--r-- | rpki/gui/app/migrations/0001_initial.py | 8 | ||||
-rw-r--r-- | rpki/gui/models.py | 91 |
2 files changed, 61 insertions, 38 deletions
diff --git a/rpki/gui/app/migrations/0001_initial.py b/rpki/gui/app/migrations/0001_initial.py index 1a02dd8a..73884581 100644 --- a/rpki/gui/app/migrations/0001_initial.py +++ b/rpki/gui/app/migrations/0001_initial.py @@ -72,8 +72,8 @@ class Migration(migrations.Migration): name='ResourceRangeAddressV4', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('prefix_min', rpki.gui.models.IPv4AddressField(db_index=True)), - ('prefix_max', rpki.gui.models.IPv4AddressField(db_index=True)), + ('prefix_min', rpki.gui.models.IPAddressField(db_index=True)), + ('prefix_max', rpki.gui.models.IPAddressField(db_index=True)), ('cert', models.ForeignKey(related_name='address_ranges', to='app.ResourceCert')), ], options={ @@ -85,8 +85,8 @@ class Migration(migrations.Migration): name='ResourceRangeAddressV6', fields=[ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)), - ('prefix_min', rpki.gui.models.IPv6AddressField(db_index=True)), - ('prefix_max', rpki.gui.models.IPv6AddressField(db_index=True)), + ('prefix_min', rpki.gui.models.IPAddressField(db_index=True)), + ('prefix_max', rpki.gui.models.IPAddressField(db_index=True)), ('cert', models.ForeignKey(related_name='address_ranges_v6', to='app.ResourceCert')), ], options={ diff --git a/rpki/gui/models.py b/rpki/gui/models.py index ced14926..b327333c 100644 --- a/rpki/gui/models.py +++ b/rpki/gui/models.py @@ -24,43 +24,66 @@ import rpki.resource_set import rpki.POW -class IPv6AddressField(models.Field): - "Field large enough to hold a 128-bit unsigned integer." - - __metaclass__ = models.SubfieldBase - - def db_type(self, connection): - return 'binary(16)' - - def to_python(self, value): - if isinstance(value, rpki.POW.IPAddress): +class IPAddressField(models.CharField): + """ + Field class for rpki.POW.IPAddress, stored as zero-padded + hexadecimal so lexicographic order is identical to numeric order. + """ + + # Django's CharField type doesn't distinguish between the length + # of the human readable form and the length of the storage form, + # so we have to leave room for IPv6 punctuation even though we + # only store hexadecimal digits and thus will never use the full + # width of the database field. Price we pay for portability. + # + # Documentation on the distinction between the various conversion + # methods is fairly opaque, to put it politely, and we have to + # handle database engines which sometimes return buffers or other + # classes instead of strings, so the conversions are a bit + # finicky. If this goes haywire, your best bet is probably to + # litter the code with logging.debug() calls and debug by printf. + + def __init__(self, *args, **kwargs): + kwargs["max_length"] = 40 + super(IPAddressField, self).__init__(*args, **kwargs) + + def deconstruct(self): + name, path, args, kwargs = super(IPAddressField, self).deconstruct() + del kwargs["max_length"] + return name, path, args, kwargs + + @staticmethod + def _value_to_ipaddress(value): + if value is None or isinstance(value, rpki.POW.IPAddress): return value - return rpki.POW.IPAddress.fromBytes(value) - - def get_db_prep_value(self, value, connection, prepared): - """ - Note that we add a custom conversion to encode long values as hex - strings in SQL statements. See settings.get_conv() for details. - """ - - return value.toBytes() - - -class IPv4AddressField(models.Field): - "Wrapper around rpki.POW.IPAddress." + value = str(value) + if ":" in value or "." in value: + return rpki.POW.IPAddress(value) + else: + return rpki.POW.IPAddress.fromBytes(value.decode("hex")) - __metaclass__ = models.SubfieldBase - - def db_type(self, connection): - return 'int UNSIGNED' + def from_db_value(self, value, expression, connection, context): + # Can't use super() here, see Django documentation. + return self._value_to_ipaddress(value) def to_python(self, value): + return self._value_to_ipaddress( + super(IPAddressField, self).to_python(value)) + + @staticmethod + def _hex_from_ipaddress(value): if isinstance(value, rpki.POW.IPAddress): + return value.toBytes().encode("hex") + else: return value - return rpki.POW.IPAddress(value, version=4) - def get_db_prep_value(self, value, connection, prepared): - return long(value) + def get_prep_value(self, value): + return super(IPAddressField, self).get_prep_value( + self._hex_from_ipaddress(value)) + + def get_db_prep_value(self, value, connection, prepared = False): + return self._hex_from_ipaddress( + super(IPAddressField, self).get_db_prep_value(value, connection, prepared)) class Prefix(models.Model): @@ -103,8 +126,8 @@ class PrefixV4(Prefix): range_cls = rpki.resource_set.resource_range_ipv4 - prefix_min = IPv4AddressField(db_index=True, null=False) - prefix_max = IPv4AddressField(db_index=True, null=False) + prefix_min = IPAddressField(db_index=True, null=False) + prefix_max = IPAddressField(db_index=True, null=False) class Meta(Prefix.Meta): abstract = True @@ -115,8 +138,8 @@ class PrefixV6(Prefix): range_cls = rpki.resource_set.resource_range_ipv6 - prefix_min = IPv6AddressField(db_index=True, null=False) - prefix_max = IPv6AddressField(db_index=True, null=False) + prefix_min = IPAddressField(db_index=True, null=False) + prefix_max = IPAddressField(db_index=True, null=False) class Meta(Prefix.Meta): abstract = True |