Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/phonenumber_field/modelfields.py: 82%
66 statements
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
« prev ^ index » next coverage.py v6.4.4, created at 2023-07-17 14:22 -0600
1from django.conf import settings
2from django.core import checks
3from django.db import models
4from django.utils.encoding import force_str
5from django.utils.translation import gettext_lazy as _
7from phonenumber_field import formfields
8from phonenumber_field.phonenumber import PhoneNumber, to_python, validate_region
9from phonenumber_field.validators import validate_international_phonenumber
12class PhoneNumberDescriptor:
13 """
14 The descriptor for the phone number attribute on the model instance.
15 Returns a PhoneNumber when accessed so you can do stuff like::
17 >>> instance.phone_number.as_international
19 Assigns a phone number object on assignment so you can do::
21 >>> instance.phone_number = PhoneNumber(...)
23 or,
25 >>> instance.phone_number = '+414204242'
26 """
28 def __init__(self, field):
29 self.field = field
31 def __get__(self, instance, owner):
32 if instance is None: 32 ↛ 33line 32 didn't jump to line 33, because the condition on line 32 was never true
33 return self
35 # The instance dict contains whatever was originally assigned in
36 # __set__.
37 if self.field.name in instance.__dict__: 37 ↛ 40line 37 didn't jump to line 40, because the condition on line 37 was never false
38 value = instance.__dict__[self.field.name]
39 else:
40 instance.refresh_from_db(fields=[self.field.name])
41 value = getattr(instance, self.field.name)
42 return value
44 def __set__(self, instance, value):
45 instance.__dict__[self.field.name] = to_python(value, region=self.field.region)
48class PhoneNumberField(models.CharField):
49 attr_class = PhoneNumber
50 descriptor_class = PhoneNumberDescriptor
51 default_validators = [validate_international_phonenumber]
53 description = _("Phone number")
55 def __init__(self, *args, region=None, **kwargs):
56 """
57 :keyword str region: 2-letter country code as defined in ISO 3166-1.
58 When not supplied, defaults to :setting:`PHONENUMBER_DEFAULT_REGION`
59 :keyword int max_length: The maximum length of the underlying char field.
60 """
61 kwargs.setdefault("max_length", 128)
62 super().__init__(*args, **kwargs)
63 self._region = region
65 @property
66 def region(self):
67 return self._region or getattr(settings, "PHONENUMBER_DEFAULT_REGION", None)
69 def check(self, **kwargs):
70 errors = super().check(**kwargs)
71 errors.extend(self._check_region())
72 return errors
74 def _check_region(self):
75 try:
76 validate_region(self.region)
77 except ValueError as e:
78 return [checks.Error(force_str(e), obj=self)]
79 return []
81 def get_prep_value(self, value):
82 """
83 Perform preliminary non-db specific value checks and conversions.
84 """
85 if not value:
86 return super().get_prep_value(value)
88 if isinstance(value, PhoneNumber): 88 ↛ 92line 88 didn't jump to line 92, because the condition on line 88 was never false
89 parsed_value = value
90 else:
91 # Convert the string to a PhoneNumber object.
92 parsed_value = to_python(value)
94 if parsed_value.is_valid(): 94 ↛ 101line 94 didn't jump to line 101, because the condition on line 94 was never false
95 # A valid phone number. Normalize it for storage.
96 format_string = getattr(settings, "PHONENUMBER_DB_FORMAT", "E164")
97 fmt = PhoneNumber.format_map[format_string]
98 value = parsed_value.format_as(fmt)
99 else:
100 # Not a valid phone number. Store the raw string.
101 value = parsed_value.raw_input
103 return super().get_prep_value(value)
105 def contribute_to_class(self, cls, name, *args, **kwargs):
106 super().contribute_to_class(cls, name, *args, **kwargs)
107 setattr(cls, self.name, self.descriptor_class(self))
109 def deconstruct(self):
110 name, path, args, kwargs = super().deconstruct()
111 kwargs["region"] = self._region
112 return name, path, args, kwargs
114 def formfield(self, **kwargs):
115 defaults = {
116 "form_class": formfields.PhoneNumberField,
117 "region": self.region,
118 "error_messages": self.error_messages,
119 }
120 defaults.update(kwargs)
121 return super().formfield(**defaults)