Login

Tuned IPAddressField with IPv4 & IPv6 support using Postgres Network Field type

Author:
illsci
Posted:
April 20, 2009
Language:
Python
Version:
1.0
Tags:
field model ipy custom ipv6 ip ip-addresses ipv4 postgresql-network-field ip-address
Score:
0 (after 0 ratings)

I wanted to store ipv4 and ipv6 ip's in django but I wanted to use the postgresql inet network field type:

http://www.postgresql.org/docs/8.3/static/datatype-net-types.html

and I wanted to use IPy.py IP objects in python. I followed these very helpful examples along with the django documentation:

http://vaig.be/2009/03/numeric-ip-field-for-django.html http://www.djangosnippets.org/snippets/1381/

It took me awhile to figure out how this works (not that I completely understand it now..) and figured I would share it. If anyone finds problems with this or can make it better I will definitely use it.

 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
from django.db import models
from django.contrib import admin

from django.forms import ValidationError as FormValidationError
from django.core.exceptions import ValidationError
from django.forms import fields, widgets

from decimal import Decimal
from IPy import IP
 
class IPAddressFormField(fields.Field):
    default_error_messages = {
        'invalid': u'Enter a valid IPv4 or IPv6 address.',
    }

    def clean(self, value):
        'Method for validating IPs on forms'
        if value in fields.EMPTY_VALUES:
            return u''
            
        try:
            IP(value)
        except Exception, e:
            raise FormValidationError(self.error_messages['invalid'])

        return super(IPAddressFormField, self).clean(value)

class IPAddressWidget(widgets.TextInput):
    def render(self, name, value, attrs=None):
        if isinstance(value, IP):
            value = value.strNormal()
    
        return super(IPAddressWidget, self).render(name, value, attrs)

class IPAddressField(models.Field):

    __metaclass__ = models.SubfieldBase

    def db_type(self):
        return 'inet'

    def to_python(self, value):
        if not value or ((isinstance(value, str) or isinstance(value, unicode)) and value == ''):
            return None

        try:
            value = IP(value)
        except Exception, e:
            raise ValidationError(e)

        return value

    def get_db_prep_value(self, value):
        if not value:
            return None
        else:
            return unicode(value)

    def formfield(self, **kwargs):
        defaults = {
            'form_class': IPAddressFormField, 
            'widget': IPAddressWidget 
        }
        defaults.update(kwargs)
        return super(IPAddressField, self).formfield(**defaults)

More like this

  1. Include entire networks in INTERNAL_IPS setting by pmclanahan 6 years, 3 months ago
  2. Use the development server on the network by perevilas 4 years, 4 months ago
  3. IPAddressField with CIDR support by SeniorHuevo 5 years, 3 months ago
  4. Block IP addresses by pill 7 years, 2 months ago
  5. Test IP against IP address+Subnet whitelist by mtigas 5 years, 12 months ago

Comments

diverman (on April 20, 2009):

I don't like error message: 'Enter a valid IPv4 or IPv6 address.'. Is is so ambiguous :-/ In my snippet no.1381, the form validation error uses a message returned by IPy.

#

Please login first before commenting.