python - 如何查找在 Django-admin 中存储为整数的自定义 ip 地址字段?

标签 python mysql django

在我的 Django 模型中,我创建了自定义的 MyIPAddressField,它作为整数存储在 mysql 后端。为此,我实现了 to_python、get_db_prep_value、get_iternal_type(返回 PositiveIntegerField)和 formfield 方法(使用常用 IPAddressField 作为 form_class)。

唯一的问题是在 ModelAdmin 中的内置搜索等情况下的字段查找。那么,问题是如何实现 get_db_prep_lookup 来执行基于字符串的查找类型,如“contains”、“regex”、“startswith”、“endswith”?

Mysql 有特殊函数 inet_ntoa() 但我不知道如何指示 ORM 在管理搜索查询中使用它。例如:SELECT inet_ntoa(ip_address) as ip FROM table WHERE ip LIKE '%search_term%'。为什么自定义字段在 python 端执行类型转换而不在数据库端执行类型转换?

EDIT1:可能还有另一种解决搜索问题的方法 - 不要将整数列转换为字符串,而是将搜索参数拆分为子网/掩码并执行一些二进制数学运算以将它们与整数 IP 值进行比较。

EDIT2:到目前为止,这是我的代码:

模型.py:

class MyIPField(models.Field):
    empty_strings_allowed = False

    __metaclass__ = models.SubfieldBase

    def get_db_prep_value(self, value):
        if value is None: return None
        return unpack('!L', inet_aton(value))[0]

    def get_internal_type(self):
        return "PositiveIntegerField"

    def to_python(self, value):
         if type(value).__name__ in ('NoneType', 'unicode'): return value
         return inet_ntoa(pack('!L', value))

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


class MyManager(models.Manager):
    def get_query_set(self):
        return super(MyManager, self).get_query_set().extra(select={'fakeip': "inet_ntoa(ip)"})

class Address(models.Model):
    # ... other fields are skipped (Note: there was several foreign keys)
    ip = MyIPField(u"IP address", unique=True)

    objects = AddressManager()

    def __unicode__(self):
            return self.ip

管理员.py:

class AddressAdmin(admin.ModelAdmin):
    list_display = ('address',)  # ... some fields are skipped from this example
    list_display_links = ('address',)
    search_fields = ('fakeip', )

admin.site.register(Address, AddressAdmin)

但是当我使用管理员更改列表搜索框时,出现错误“无法将关键字‘fakeip’解析为字段。选择是:ip、id”。有没有可能骗过Django,让它认为fakeip是一个真实的字段?

使用标准 IPAddressField(基于字符串)不适合我的需要,并且切换到以正确格式存储的 Postgres。

我还查看了 Django 管理内部结构(options.py 和 views/main.py),我发现没有简单的方法可以自定义 ChangeList 类或搜索机制,而无需大量复制/粘贴。我认为 Django 管理器比它更强大。

最佳答案

您可以指示 ORM 向您的 SQL 查询添加一个额外的字段,如下所示:

IPAddressModel.objects.extra(select={'ip': "inet_ntoa(ip_address)"})

这会将 SELECT inet_ntoa(ip_address) as ip 添加到查询中,并将字段 ip 添加到您的对象中。您可以在 WHERE 子句中使用新的合成字段。

你确定你真的不想要像 WHERE (ip_address & 0xffff0000) = inet_aton('192.168.0.0') 这样的东西吗?或者您是否真的想在您的日志中的某处找到所有包含数字 119 的 IP 地址?

如果 suffix 是来自 CIDR 表示法的/24:

mask = 0xffffffff ^ 0xffffffff >> suffix

添加到 WHERE 子句:

(ip_address & mask) = (inet_aton(prefix) & mask)

关于python - 如何查找在 Django-admin 中存储为整数的自定义 ip 地址字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/541115/

相关文章:

django 身份验证 ldap

python - 如何在 BeautifulSoup 中保持 Django 模板代码的有效性

python - 使用 Mutagen 处理所有接受的文件类型

python - 包含形状和它们之间的空间关系的正确数据结构

mysql - 自减级联主键

mysql - Symfony2 : Doctrine: Base table or view not found: 1146 tablename is same

python - python中赋值意味着指向地址?

android - Mysql 查询(Where)与 edittext android

django - 我需要在 Django 中为我的表单创建 forms.py 吗?

django - 领头启动时出现 ImportError : No module named my_project. wsgi 错误