Login

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

Author:
illsci
Posted:
April 20, 2009
Language:
Python
Version:
1.0
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. Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 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.