fields.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. from django.core.exceptions import ValidationError
  2. from django.core.validators import MinValueValidator, MaxValueValidator
  3. from django.db import models
  4. from django.utils.translation import gettext as _
  5. from netaddr import AddrFormatError, IPNetwork
  6. from . import lookups, validators
  7. from .formfields import IPNetworkFormField
  8. __all__ = (
  9. 'ASNField',
  10. 'IPAddressField',
  11. 'IPNetworkField',
  12. )
  13. # BGP ASN bounds
  14. BGP_ASN_MIN = 1
  15. BGP_ASN_MAX = 2**32 - 1
  16. BGP_ASN_ASDOT_BASE = 2**16
  17. class BaseIPField(models.Field):
  18. def python_type(self):
  19. return IPNetwork
  20. def from_db_value(self, value, expression, connection):
  21. return self.to_python(value)
  22. def get_internal_type(self):
  23. return 'CharField'
  24. def to_python(self, value):
  25. if not value:
  26. return value
  27. try:
  28. # Always return a netaddr.IPNetwork object. (netaddr.IPAddress does not provide a mask.)
  29. return IPNetwork(value)
  30. except AddrFormatError:
  31. raise ValidationError(_("Invalid IP address format: {address}").format(address=value))
  32. except (TypeError, ValueError) as e:
  33. raise ValidationError(e)
  34. def get_prep_value(self, value):
  35. if not value:
  36. return None
  37. if isinstance(value, list):
  38. return [str(self.to_python(v)) for v in value]
  39. return str(self.to_python(value))
  40. def form_class(self):
  41. return IPNetworkFormField
  42. def formfield(self, **kwargs):
  43. defaults = {'form_class': self.form_class()}
  44. defaults.update(kwargs)
  45. return super().formfield(**defaults)
  46. class IPNetworkField(BaseIPField):
  47. """
  48. IP prefix (network and mask)
  49. """
  50. description = 'PostgreSQL CIDR field'
  51. default_validators = [validators.prefix_validator]
  52. def db_type(self, connection):
  53. return 'cidr'
  54. IPNetworkField.register_lookup(lookups.IExact)
  55. IPNetworkField.register_lookup(lookups.EndsWith)
  56. IPNetworkField.register_lookup(lookups.IEndsWith)
  57. IPNetworkField.register_lookup(lookups.StartsWith)
  58. IPNetworkField.register_lookup(lookups.IStartsWith)
  59. IPNetworkField.register_lookup(lookups.Regex)
  60. IPNetworkField.register_lookup(lookups.IRegex)
  61. IPNetworkField.register_lookup(lookups.NetContained)
  62. IPNetworkField.register_lookup(lookups.NetContainedOrEqual)
  63. IPNetworkField.register_lookup(lookups.NetContains)
  64. IPNetworkField.register_lookup(lookups.NetContainsOrEquals)
  65. IPNetworkField.register_lookup(lookups.NetFamily)
  66. IPNetworkField.register_lookup(lookups.NetMaskLength)
  67. class IPAddressField(BaseIPField):
  68. """
  69. IP address (host address and mask)
  70. """
  71. description = 'PostgreSQL INET field'
  72. def db_type(self, connection):
  73. return 'inet'
  74. IPAddressField.register_lookup(lookups.IExact)
  75. IPAddressField.register_lookup(lookups.EndsWith)
  76. IPAddressField.register_lookup(lookups.IEndsWith)
  77. IPAddressField.register_lookup(lookups.StartsWith)
  78. IPAddressField.register_lookup(lookups.IStartsWith)
  79. IPAddressField.register_lookup(lookups.Regex)
  80. IPAddressField.register_lookup(lookups.IRegex)
  81. IPAddressField.register_lookup(lookups.NetContained)
  82. IPAddressField.register_lookup(lookups.NetContainedOrEqual)
  83. IPAddressField.register_lookup(lookups.NetContains)
  84. IPAddressField.register_lookup(lookups.NetContainsOrEquals)
  85. IPAddressField.register_lookup(lookups.NetHost)
  86. IPAddressField.register_lookup(lookups.NetIn)
  87. IPAddressField.register_lookup(lookups.NetHostContained)
  88. IPAddressField.register_lookup(lookups.NetFamily)
  89. IPAddressField.register_lookup(lookups.NetMaskLength)
  90. IPAddressField.register_lookup(lookups.Host)
  91. IPAddressField.register_lookup(lookups.Inet)
  92. class ASNField(models.BigIntegerField):
  93. description = '32-bit ASN field'
  94. default_validators = [
  95. MinValueValidator(BGP_ASN_MIN),
  96. MaxValueValidator(BGP_ASN_MAX),
  97. ]
  98. def formfield(self, **kwargs):
  99. defaults = {
  100. 'min_value': BGP_ASN_MIN,
  101. 'max_value': BGP_ASN_MAX,
  102. }
  103. defaults.update(**kwargs)
  104. return super().formfield(**defaults)
  105. @staticmethod
  106. def to_asdot(value) -> str:
  107. """
  108. Return ASDOT notation for AS numbers greater than 16 bits.
  109. """
  110. if value is None:
  111. return ''
  112. if value >= BGP_ASN_ASDOT_BASE:
  113. hi, lo = divmod(value, BGP_ASN_ASDOT_BASE)
  114. return f'{hi}.{lo}'
  115. return str(value)