You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

84 lines
2.7 KiB

from ipaddress import ip_network
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError
from django.db import models
from django.forms.fields import CharField
def validate_ipv46_address_with_subnet(v: str):
try:
ip = ip_network(v)
return str(ip)
except ValueError as e:
raise ValidationError(e)
class GenericIPAddressFormField(CharField):
def __init__(self, unpack_ipv4=False, *args, **kwargs):
self.unpack_ipv4 = unpack_ipv4
self.default_validators = validate_ipv46_address_with_subnet,
del kwargs['protocol']
super(GenericIPAddressFormField, self).__init__(*args, **kwargs)
def to_python(self, value):
if value in self.empty_values:
return ''
value = value.strip()
if value and ':' in value:
ip = ip_network(value, strict=False)
return ip.compressed
return value
class GenericIpAddressWithPrefix(models.GenericIPAddressField):
description = _("IP address with prefix length, or subnet for ipv4")
def __init__(self, prefix=None, *args, **kwargs):
self.prefix = prefix
super(GenericIpAddressWithPrefix, self).__init__(*args, **kwargs)
self.default_error_messages['invalid'] = _('Enter a valid IPv4 or IPv6 address with prefix length.')
self.max_length = 43
def deconstruct(self):
name, path, args, kwargs = super(GenericIpAddressWithPrefix, self).deconstruct()
if kwargs.get("max_length") == 43:
del kwargs['max_length']
return name, path, args, kwargs
@property
def validators(self):
return validate_ipv46_address_with_subnet,
def to_python(self, value):
if value is None:
return None
value = value.strip()
if ':' in value:
ip = ip_network(value)
return ip.compressed
return value
def get_db_prep_value(self, value, connection, prepared=False):
if not prepared:
value = self.get_prep_value(value)
return connection.ops.adapt_ipaddressfield_value(value)
def get_prep_value(self, value):
value = super(GenericIpAddressWithPrefix, self).get_prep_value(value)
if value is None:
return None
if value and ':' in value:
try:
return ip_network(value)
except ValidationError:
pass
return value
def formfield(self, **kwargs):
defaults = {
'protocol': self.protocol,
'form_class': GenericIPAddressFormField,
}
defaults.update(kwargs)
return super(GenericIpAddressWithPrefix, self).formfield(**defaults)