I am writing a Django application that stores IP addresses with optional routing information. One of the fields for the IP model I have created is nexthop
(for next-hop routes), which will usually be empty. Originally we intended to use MySQL, but now project requirements have changed to use PostgreSQL.
Here is a stripped down version of my model:
class IP(models.Model):
address = models.IPAddressField()
netmask = models.IPAddressField(default='255.255.255.255')
nexthop = models.IPAddressField(null=True, blank=True, default=None)
active = models.BooleanField('is active?', default=1)
So, with MySQL I did not have a problem leaving the nexthop
field empty. However, now that I switched the development environment to Postgres, we've run into a known issue in Django 1.1.1 in which a blank IP address raises a DataError
invalid input syntax for type inet: ""
LINE 1: ...-14 13:07:29', 1, E'1.2.3.4', E'255.255.255.255', E'', true)
^
As you can see, it bombs because it is trying to insert an empty string when the column will only accept a NULL
.
I have a very real need to be able to keep this field empty, because if an IP doesn't have a next-hop, then its behavior changes.
Short of hacking the Django code manually, which is my ultimate last resort, I have also thought of defaulting next-hop to 255.255.255.255 and wrapping some business logic around that (i.e. If next-hop is 255.255.255.255, treat as normal route), but that just feels like a hack.
I would like to know if there are any suggestions on a better way to do this that would not require hacking Django or writing hacky logic, or if there is a completely different approach altogether that can satisfy my requirement.
Thanks in advance!
Edit: Interim Solution
For the time-being (as an interstitial fix) I decided to go with the sentinel value for the next-hop:
In the model:
IP_NEXTHOP_SENTINEL = '255.255.255.255'
class IP(models.Model):
nexthop = models.IPAddressField(
null=True,
blank=True,
default=IP_NEXTHOP_SENTINEL,
help_text='Use %s to indicate no next-hop' % IP_NEXTHOP_SENTINEL
)
def save(self, *args, **kwargs):
## hack for Django #5622 (http://code.djangoproject.com/ticket/5622)
if self.nexthop and self.nexthop == IP_NEXTHOP_SENTINEL:
self.nexthop = None
Overview:
Creation of IP
objects outside of the admin portal works as intended, which is why I kept the null=True
argument on the nexthop
field. The only place where 255.255.255.255 would ever be set as the next-hop would be through the admin portal, so I decided that overloading s开发者_高级运维ave()
to always replace the sentinel with None
would give me the final result I desire and it doesn't really feel too much like a hack.
Thanks for your input on this!
If you can convince the devs to accept one of the patches, I'd say just run a patched copy of Django until the patched version lands. If not, then it might be less headache to just use a sentinel value, as you suggested, even though it is a hack. You might also just use a regular CharField
instead of an IPAddressField
, but then you get stuck having to maintain validation logic on your own.
Have you tried just using blank=True
for nexthop
, rather than both blank=True
and null=True
? As noted in the Django docs:
Only use null=True for non-string fields such as integers, booleans and dates.
And what about using empty string as sentinel, instead of 255.255.255.255 ?
As admin back-end stores empty field as empty string (when blank=true
), this solution has the advantage to be transparent for the user and doesn't force him to use a faked value...
精彩评论