formfields.py 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. from django import forms
  2. from django.core.exceptions import ValidationError
  3. from django.core.validators import validate_ipv4_address, validate_ipv6_address
  4. from django.utils.translation import gettext_lazy as _
  5. from netaddr import IPAddress, IPNetwork, AddrFormatError
  6. #
  7. # Form fields
  8. #
  9. class IPAddressFormField(forms.Field):
  10. default_error_messages = {
  11. 'invalid': _("Enter a valid IPv4 or IPv6 address (without a mask)."),
  12. }
  13. def to_python(self, value):
  14. if not value:
  15. return None
  16. if isinstance(value, IPAddress):
  17. return value
  18. # netaddr is a bit too liberal with what it accepts as a valid IP address. For example, '1.2.3' will become
  19. # IPAddress('1.2.0.3'). Here, we employ Django's built-in IPv4 and IPv6 address validators as a sanity check.
  20. try:
  21. validate_ipv4_address(value)
  22. except ValidationError:
  23. try:
  24. validate_ipv6_address(value)
  25. except ValidationError:
  26. raise ValidationError(_("Invalid IPv4/IPv6 address format: {address}").format(address=value))
  27. try:
  28. return IPAddress(value)
  29. except ValueError:
  30. raise ValidationError(_('This field requires an IP address without a mask.'))
  31. except AddrFormatError:
  32. raise ValidationError(_("Please specify a valid IPv4 or IPv6 address."))
  33. class IPNetworkFormField(forms.Field):
  34. default_error_messages = {
  35. 'invalid': _("Enter a valid IPv4 or IPv6 address (with CIDR mask)."),
  36. }
  37. def to_python(self, value):
  38. if not value:
  39. return None
  40. if isinstance(value, IPNetwork):
  41. return value
  42. # Ensure that a subnet mask has been specified. This prevents IPs from defaulting to a /32 or /128.
  43. if len(value.split('/')) != 2:
  44. raise ValidationError(_('CIDR mask (e.g. /24) is required.'))
  45. try:
  46. return IPNetwork(value)
  47. except AddrFormatError:
  48. raise ValidationError(_("Please specify a valid IPv4 or IPv6 address."))