You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest Framework如何为PostgreSQL InetAddressField实现合适过滤器?

解决方案:DRF中实现PostgreSQL inet字段的IP/子网过滤器

一、使用成熟第三方库django-postgres-netfields

这是专门为PostgreSQL网络字段(inet、cidr、macaddr等)打造的Django扩展,完美适配DRF过滤需求。

1. 安装与配置

  • 安装依赖:pip install django-postgres-netfields
  • 在项目settings.py的INSTALLED_APPS中添加:
    INSTALLED_APPS = [
        # ...其他应用
        'netfields',
    ]
    

2. 定义模型

用库提供的字段替换原生字段,直接映射PostgreSQL的网络类型:

from django.db import models
from netfields import InetField, CidrField

class IPRecord(models.Model):
    ip_address = InetField()  # 存储单个IP或子网
    subnet = CidrField(null=True, blank=True)  # 专门存储子网(带前缀)
    ip_range_start = InetField(null=True, blank=True)
    ip_range_end = InetField(null=True, blank=True)

3. 实现DRF过滤器

结合django-filter使用库自带的过滤组件:

  • 先安装django-filter:pip install django-filter
  • 在settings.py配置DRF过滤器后端:
    REST_FRAMEWORK = {
        'DEFAULT_FILTER_BACKENDS': [
            'django_filters.rest_framework.DjangoFilterBackend',
        ],
    }
    
  • 编写过滤器类,直接调用封装好的PostgreSQL网络操作符:
import django_filters
from netfields.filters import InetFilter
from .models import IPRecord

class IPRecordFilter(django_filters.FilterSet):
    # 精确匹配IP
    exact_ip = InetFilter(field_name='ip_address', lookup_expr='exact')
    # 检测IP是否属于数据库中的子网(对应PostgreSQL的<<操作符)
    in_subnet = InetFilter(field_name='subnet', lookup_expr='contains')
    # 检测IP是否在指定IP范围内
    in_ip_range = django_filters.MethodFilter(action='filter_ip_range')

    def filter_ip_range(self, queryset, value):
        # value为传入的待检测IP,利用inet类型的数值比较特性
        return queryset.filter(
            ip_range_start__lte=value,
            ip_range_end__gte=value
        )

    class Meta:
        model = IPRecord
        fields = ['exact_ip', 'in_subnet', 'in_ip_range']
  • 在视图中绑定过滤器:
from rest_framework import viewsets
from .models import IPRecord
from .serializers import IPRecordSerializer
from .filters import IPRecordFilter

class IPRecordViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = IPRecord.objects.all()
    serializer_class = IPRecordSerializer
    filterset_class = IPRecordFilter

二、无第三方库的自定义实现

如果不想依赖外部包,可以手动利用Django的原生能力实现:

1. 模型字段处理

Django的GenericIPAddressField在PostgreSQL中默认映射为inet类型,直接使用即可:

from django.db import models

class IPRecord(models.Model):
    ip_address = models.GenericIPAddressField(protocol='both', unpack_ipv4=True)
    subnet = models.GenericIPAddressField(protocol='both', unpack_ipv4=True)
    ip_range_start = models.GenericIPAddressField(protocol='both', unpack_ipv4=True)
    ip_range_end = models.GenericIPAddressField(protocol='both', unpack_ipv4=True)

2. 自定义过滤器逻辑

通过RawSQL调用PostgreSQL原生网络操作符:

import django_filters
from django.db.models import RawSQL
from .models import IPRecord

class IPRecordFilter(django_filters.FilterSet):
    exact_ip = django_filters.CharFilter(field_name='ip_address', lookup_expr='exact')
    in_subnet = django_filters.CharFilter(method='filter_in_subnet')
    in_ip_range = django_filters.CharFilter(method='filter_ip_range')

    def filter_in_subnet(self, queryset, name, value):
        # 直接调用PostgreSQL的<<操作符判断IP是否在子网内
        return queryset.annotate(
            is_in_subnet=RawSQL("%s << subnet", (value,))
        ).filter(is_in_subnet=True)

    def filter_ip_range(self, queryset, name, value):
        return queryset.filter(
            ip_range_start__lte=value,
            ip_range_end__gte=value
        )

    class Meta:
        model = IPRecord
        fields = ['exact_ip', 'in_subnet', 'in_ip_range']

三、关键注意事项

  • 子网存储需带前缀(如192.168.1.0/24),否则PostgreSQL无法识别为子网类型
  • IP范围查询需保证ip_range_start小于等于ip_range_end,可在模型的clean方法中添加验证逻辑
  • 优先选择django-postgres-netfields,它封装了所有PostgreSQL网络操作符,还提供了序列化器、表单字段的原生支持

内容的提问来源于stack exchange,提问作者Empusas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 20:41:06