Tuned IPAddressField with IPv4 & IPv6 support
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | """
IPAddressField for models with IPv4 & IPv6 support
Requires: IPy
http://software.inl.fr/trac/wiki/IPy http://c0re.23.nu/c0de/IPy/
On Debian/Ubuntu: apt-get install python-ipy
Example:
class Host(models.Model):
hostname = models.CharField()
ip = IPAddressField()
>>> my_host = Host()
>>> my_host.hostname = 'server'
>>> my_host.ip = '192.168.0.1'
>>> my_host.save()
>>> my_host.ip
IP('192.168.0.1')
>>> my_host.ip = 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'
>>> dir(my_host.ip)
['NoPrefixForSingleIp', 'WantPrefixLen', '__add__', '__cmp__', '__contains__',
'__doc__', '__getitem__', '__hash__', '__init__', '__len__', '__module__',
'__nonzero__', '__repr__', '__str__', '_ipversion', '_prefixlen', '_printPrefix',
'broadcast', 'int', 'ip', 'iptype', 'len', 'make_net', 'net', 'netmask', 'overlaps',
'prefixlen', 'reverseName', 'reverseNames', 'strBin', 'strCompressed', 'strDec',
'strFullsize', 'strHex', 'strNetmask', 'strNormal', 'version']
>>> my_host.ip.reverseName()
'f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.ip6.arpa.'
>>> my_host.ip.version()
6
>>> my_host.ip = '1.2.3.4.5'
ValidationError: IPv4 Address with more than 4 bytes
>>> my_host.ip = 'aa:dd:xx'
ValidationError: 'aa:dd:xx': Invalid IPv6 address: should have 8 hextets
"""
from django.forms import ValidationError as FormValidationError
from django.core.exceptions import ValidationError
from django.forms import fields, widgets
from django.db import models
from decimal import Decimal
from IPy import IP
IP.__long__ = IP.int
def clean_ip(ip):
'Method for validating IPs on forms'
try:
IP(ip)
except Exception, e:
raise FormValidationError(e)
return ip
class IPAddressWidget(widgets.TextInput):
def render(self, name, value, attrs=None):
if isinstance(value, IP):
value = unicode(value)
return super(IPAddressWidget, self).render(name, value, attrs)
class IPAddressField(models.Field):
__metaclass__ = models.SubfieldBase
def db_type(self):
return 'numeric(39, 0)'
def to_python(self, value):
if not value:
return None
elif isinstance(value, Decimal):
value = long(value)
try:
return IP(value)
except Exception, e:
raise ValidationError(e)
def get_db_prep_lookup(self, lookup_type, value):
try:
if lookup_type in ('range', 'in'):
return [self.get_db_prep_value(v) for v in value]
return [self.get_db_prep_value(value)]
except ValidationError:
return super(IPAddressField, self).get_db_prep_lookup(lookup_type, value)
def get_db_prep_value(self, value):
try:
return long(self.to_python(value))
except TypeError:
return None
def formfield(self, **kwargs):
defaults = {
'form_class': fields.CharField,
'widget': IPAddressWidget,
}
defaults.update(kwargs)
return super(IPAddressField, self).formfield(**defaults)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 1 week ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 2 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 6 months ago
Comments
Great snippet!
Instead of "return None" I'd "return IP(0)" just in case you need to compare the results with another IP instance. IPy doesn't like comparing IP's with non IP objects (like None or a string).
#
Please login first before commenting.