Commits

Owen Nelson committed 0fd952f

IPy.IP raises AttributeError when compared to non-IP instance. Provides a subclass to allow these comparisions.

  • Participants
  • Parent commits 70d7881

Comments (0)

Files changed (7)

 include LICENSE
-include README
+include README.rst
 

File README

-.. -*- restructuredtext -*-
-
-django-ipyfield
-===============
-
-``ipyfield`` provides a model field for 
-`django <https://www.djangoproject.com>`_
-that allows the storage of an ip address as a ``BigInt`` on the db side by 
-using `IPy <http://pypi.python.org/pypi/IPy/>`_ to handle 
-conversion to an ``IPy.IP`` instance (or ``None``) on the python side. 
-
-Wut?
-----
-
-In its way, it gives us a way to store both **ipv4** and **ipv6** consistently
-without having to throw them in long charfields. Also, it gives us an easy way
-to validate data as it comes in, while giving us access to additional meta
-information (basically everything that makes 
-`IPy <http://pypi.python.org/pypi/IPy/>`_ so awesome).
-
-
-Installation
-------------
-
-Add this to your django project by installing with ``pip``: ::
-    
-    pip install django-ipyfield
-
-or with ``easy_install``: ::
-
-    easy_install django-ipyfield
-
-
-
-Usage
------
-
-In your models, do something like the following: ::
-    
-    from django.db import models
-    from ipyfield.models import IPyField
-
-    class MyModel(models.Model):
-
-        # the regular params should work well enough here
-        ipaddr = IPyField()
-        # ... and so on
-
-
-From here, any assignments to ``obj.ipaddr`` can be considered a constructor
-argument to a new ``IPy.IP`` instance. Anything ``IP()`` can use to make a new
-object can be used.
-
-When making queries, I added one extra piece of syntactical sugar. For 
-``__in`` (range) lookups, you can pass a **CIDR** notation address range, for 
-example: ::
-    
-    MyModel.objects.filter(ipaddr__in='10.0.0.0/24')
-
-Currently you need to use this form of notation supported for this kind of 
-query. For now, if you need to use a ``prefix-netmask`` style notation, pass it 
-to ``IPy.IP`` yourself and use the resulting instance as your filter parameter.
-
-
+.. -*- restructuredtext -*-
+
+django-ipyfield
+===============
+
+``ipyfield`` provides a model field for 
+`django <https://www.djangoproject.com>`_
+that allows the storage of an ip address as a ``BigInt`` on the db side by 
+using `IPy <http://pypi.python.org/pypi/IPy/>`_ to handle 
+conversion to an ``IPy.IP`` instance (or ``None``) on the python side. 
+
+Wut?
+----
+
+In its way, it gives us a way to store both **ipv4** and **ipv6** consistently
+without having to throw them in long charfields. Also, it gives us an easy way
+to validate data as it comes in, while giving us access to additional meta
+information (basically everything that makes 
+`IPy <http://pypi.python.org/pypi/IPy/>`_ so awesome).
+
+
+Installation
+------------
+
+Add this to your django project by installing with ``pip``: ::
+    
+    pip install django-ipyfield
+
+or with ``easy_install``: ::
+
+    easy_install django-ipyfield
+
+
+
+Usage
+-----
+
+In your models, do something like the following: ::
+    
+    from django.db import models
+    from ipyfield.models import IPyField
+
+    class MyModel(models.Model):
+
+        # the regular params should work well enough here
+        ipaddr = IPyField()
+        # ... and so on
+
+
+From here, any assignments to ``obj.ipaddr`` can be considered a constructor
+argument to a new ``IPy.IP`` instance. Anything ``IP()`` can use to make a new
+object can be used.
+
+When making queries, I added one extra piece of syntactical sugar. For 
+``__in`` (range) lookups, you can pass a **CIDR** notation address range, for 
+example: ::
+    
+    MyModel.objects.filter(ipaddr__in='10.0.0.0/24')
+
+Currently you need to use this form of notation supported for this kind of 
+query. For now, if you need to use a ``prefix-netmask`` style notation, pass it 
+to ``IPy.IP`` yourself and use the resulting instance as your filter parameter.
+
+
+Changelog
+---------
+
+0.1.4
+    IPy.IP instance raises exception when compared to a non-IP instance. This
+    becomes an issue when you get into ModelForm validation (didn't come up when
+    only using the ORM) with regards to empty/null values.
+0.1.3
+    Basic field functionality in place.
+
+

File ipyfield/__init__.py

-__version__ = '0.1.3'
+__version__ = '0.1.4'
 
+import IPy
+
+
+class IP(IPy.IP):
+    """
+    Wrap IPy.IP to prevent AttributeError getting raised while comparing IP
+    instances to non-IP instances.
+    """
+    def __cmp__(self, other):
+        if not isinstance(other, IPy.IPint):
+            return -2
+        return super(IP, self).__cmp__(other)
+

File ipyfield/models.py

 from django.db import models
-from IPy import IP
+from ipyfield import IP
+
 
 class IPyField(models.Field):
     """
-    Handles conversion between int db column and IPy.IP instance.
+    Handles conversion between int db column and IP instance.
     """
     
     __metaclass__ = models.SubfieldBase
             return None
         return value.int()
 
+    def to_string(self, obj):
+        value = self._get_val_from_obj(obj)
+        return str(self.get_db_prep_value(value))
+
     def get_prep_lookup(self, lookup_type, value):
         if lookup_type == 'in':
             if isinstance(value, str):

File ipyfield/tests.py

 from django.db.models import Model
 from django.db import IntegrityError
 from ipyfield.models import IPyField
-from IPy import IP
+from ipyfield import IP
+import IPy
 
 
 class DummyModel(Model):
 
     __repr__ = __str__
 
+
+class IPySubclassTests(TestCase):
+    def test_ipyfield_can_compare_to_non_IP(self):
+        self.assertNotEqual(IP('::1'), 'foo')
+        self.assertNotEqual(IP('::1'), 22)
+
+    def test_IPy_cant_compare_to_non_IP(self):
+        with self.assertRaises(AttributeError):
+            self.assertNotEqual(IPy.IP('::1'), 'foo')
+        with self.assertRaises(AttributeError):
+            self.assertNotEqual(IPy.IP('::1'), 22)
+
 class IPyFieldTests(TestCase):
 
     def setUp(self):
     author_email="onelson@gmail.com",
     license="MIT",
     description="IPy.IP instances with BigInt storage for django models",
-    long_description=open('README').read(),
+    long_description=open('README.rst').read(),
     keywords="ip, models, django",
     packages=find_packages(),
     setup_requires=("setuptools"),