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
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)
|