Django 1.1.1:如何在PostgreSQL中存储空IP地址?

3 投票
3 回答
3965 浏览
提问于 2025-04-15 16:46

我正在写一个Django应用程序,用来存储IP地址和可选的路由信息。我创建的IP模型中有一个字段叫做nexthop(表示下一个跳转的路由),这个字段通常是空的。最开始我们打算使用MySQL,但现在项目的要求变成了使用PostgreSQL。

这是我模型的简化版本:

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)

在使用MySQL的时候,我没有问题让nexthop字段保持空白。然而,现在我把开发环境切换到Postgres后,我们遇到了一个在Django 1.1.1中已知的问题,空白的IP地址会引发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)
                                                             ^

正如你所看到的,它出错了,因为它试图插入一个空字符串,而这个字段只接受NULL

我非常需要这个字段可以保持空白,因为如果一个IP没有下一个跳转,它的行为就会改变。

除了手动修改Django的代码,这是我最后的选择,我还考虑过把下一个跳转的默认值设为255.255.255.255,并围绕这个值写一些业务逻辑(比如,如果下一个跳转是255.255.255.255,就当作正常路由处理),但这感觉像是个临时解决办法。

我想知道有没有更好的方法来解决这个问题,不需要修改Django或写一些不太优雅的逻辑,或者有没有完全不同的方案可以满足我的需求。

提前感谢你的帮助!

编辑:临时解决方案

目前(作为一个临时修复),我决定使用下一个跳转的哨兵值:

在模型中:

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

概述:

在管理员门户之外创建IP对象的功能正常,这就是我在nexthop字段上保留null=True参数的原因。唯一会把255.255.255.255设置为下一个跳转的地方就是通过管理员门户,所以我决定重载save()方法,让它总是把哨兵值替换为None,这样我就能得到我想要的最终结果,而且感觉并不算太像是个临时解决方案。

谢谢你的建议!

3 个回答

0

那用空字符串作为标记,代替 255.255.255.255 呢?

因为后台管理系统把空字段存储为空字符串(当 blank=true 时),这个方法对用户来说更透明,不会强迫用户使用一个假的值……

1

你有没有试过只给 nexthop 设置 blank=True,而不是同时设置 blank=Truenull=True?正如在Django文档中提到的:

只有在非字符串类型的字段,比如整数、布尔值和日期,才使用 null=True

2

如果你能说服开发者接受其中一个修复补丁,我建议你就先用这个修复过的Django版本,等正式的修复版本出来。如果说服不了的话,像你提到的那样,使用一个特殊的值可能会更简单,虽然这算是一种变通方法。你也可以用普通的 CharField 来代替 IPAddressField,但这样的话,你就得自己处理验证的逻辑了。

撰写回答