formfields.py 2.0 KB

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