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.

phonenumber.py 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. # This module is based on django-phone-number-field
  2. # https://github.com/stefanfoulis/django-phonenumber-field
  3. #
  4. # Here is the relevant copyright and permissions notice.
  5. #
  6. # Copyright (c) 2011 Stefan Foulis and contributors.
  7. #
  8. # Permission is hereby granted, free of charge, to any person
  9. # obtaining a copy of this software and associated documentation
  10. # files (the "Software"), to deal in the Software without
  11. # restriction, including without limitation the rights to use,
  12. # copy, modify, merge, publish, distribute, sublicense, and/or sell
  13. # copies of the Software, and to permit persons to whom the
  14. # Software is furnished to do so, subject to the following
  15. # conditions:
  16. from django.core import validators
  17. from django.conf import settings
  18. from django.core.exceptions import ValidationError
  19. from django.utils.translation import ugettext_lazy as _
  20. import phonenumbers
  21. class PhoneNumber(phonenumbers.phonenumber.PhoneNumber):
  22. """
  23. A extended version of phonenumbers.phonenumber.PhoneNumber that provides
  24. some neat and more pythonic, easy to access methods. This makes using a
  25. PhoneNumber instance much easier, especially in templates and such.
  26. """
  27. format_map = {
  28. 'E164': phonenumbers.PhoneNumberFormat.E164,
  29. 'INTERNATIONAL': phonenumbers.PhoneNumberFormat.INTERNATIONAL,
  30. 'NATIONAL': phonenumbers.PhoneNumberFormat.NATIONAL,
  31. 'RFC3966': phonenumbers.PhoneNumberFormat.RFC3966,
  32. }
  33. @classmethod
  34. def from_string(cls, phone_number, region=None):
  35. phone_number_obj = cls()
  36. if region is None:
  37. region = getattr(settings, 'PHONENUMBER_DEFAULT_REGION', None)
  38. phonenumbers.parse(number=phone_number, region=region,
  39. keep_raw_input=True, numobj=phone_number_obj)
  40. return phone_number_obj
  41. def __unicode__(self):
  42. format_string = getattr(
  43. settings, 'PHONENUMBER_DEFAULT_FORMAT', 'INTERNATIONAL')
  44. fmt = self.format_map[format_string]
  45. if self.is_valid():
  46. return self.format_as(fmt)
  47. return self.raw_input
  48. def is_valid(self):
  49. """
  50. checks whether the number supplied is actually valid
  51. """
  52. return phonenumbers.is_valid_number(self)
  53. def format_as(self, format):
  54. if self.is_valid():
  55. return phonenumbers.format_number(self, format)
  56. else:
  57. return self.raw_input
  58. @property
  59. def as_international(self):
  60. return self.format_as(phonenumbers.PhoneNumberFormat.INTERNATIONAL)
  61. @property
  62. def as_e164(self):
  63. return self.format_as(phonenumbers.PhoneNumberFormat.E164)
  64. @property
  65. def as_national(self):
  66. return self.format_as(phonenumbers.PhoneNumberFormat.NATIONAL)
  67. @property
  68. def as_rfc3966(self):
  69. return self.format_as(phonenumbers.PhoneNumberFormat.RFC3966)
  70. def __len__(self):
  71. return len(self.__unicode__())
  72. def __eq__(self, other):
  73. if type(other) == PhoneNumber:
  74. return self.as_e164 == other.as_e164
  75. else:
  76. return super(PhoneNumber, self).__eq__(other)
  77. def to_python(value):
  78. if value in validators.EMPTY_VALUES: # None or ''
  79. phone_number = None
  80. elif value and isinstance(value, basestring):
  81. try:
  82. phone_number = PhoneNumber.from_string(phone_number=value)
  83. except phonenumbers.phonenumberutil.NumberParseException:
  84. # the string provided is not a valid PhoneNumber.
  85. phone_number = PhoneNumber(raw_input=value)
  86. elif isinstance(value, PhoneNumber):
  87. phone_number = value
  88. return phone_number
  89. class PhoneNumberDescriptor(object):
  90. """
  91. The descriptor for the phone number attribute on the model instance.
  92. Returns a PhoneNumber when accessed so you can do stuff like::
  93. >>> instance.phone_number.as_international
  94. Assigns a phone number object on assignment so you can do::
  95. >>> instance.phone_number = PhoneNumber(...)
  96. or
  97. >>> instance.phone_number = '+414204242'
  98. """
  99. def __init__(self, field):
  100. self.field = field
  101. def __get__(self, instance=None, owner=None):
  102. if instance is None:
  103. raise AttributeError(
  104. "The '%s' attribute can only be accessed from %s instances."
  105. % (self.field.name, owner.__name__))
  106. return instance.__dict__[self.field.name]
  107. def __set__(self, instance, value):
  108. instance.__dict__[self.field.name] = to_python(value)
  109. def validate_international_phonenumber(value):
  110. phone_number = to_python(value)
  111. if phone_number and not phone_number.is_valid():
  112. raise ValidationError(_(u'The phone number entered is not valid.'))