Який найкращий спосіб зберігати номер телефону в моделях Django


131

Я зберігаю номер телефону приблизно modelтак:

phone_number = models.CharField(max_length=12)

Користувач вводить номер телефону, і я використовував би номер телефону для SMS Authenticationцього додатка, який буде використовуватися у всьому світі. Тому мені також знадобиться код країни. Чи CharFieldхороший спосіб зберігати номер телефону? І як я підтверджую номер телефону?


1
Тут є чудова пропозиція: stackoverflow.com/a/1245990/207791
Віктор Сергієнко

Відповіді:


283

Насправді ви можете заглянути в міжнародний стандартизований формат E.164 , рекомендований наприклад Twilio (які мають службу та API для відправки SMS або телефонних дзвінків через REST-запити).

Це, мабуть, буде найбільш універсальним способом зберігання телефонних номерів, особливо якщо у вас працюють міжнародні номери.

1. Телефон по телефону PhoneNumberField

Ви можете використовувати phonenumber_fieldбібліотеку. Це порт бібліотеки Google LibphoneNumber, який надає повноваження на номер телефону Android https://github.com/stefanfoulis/django-phonenumber-field

У моделі:

from phonenumber_field.modelfields import PhoneNumberField

class Client(models.Model, Importable):
    phone = PhoneNumberField(null=False, blank=False, unique=True)

За формою:

from phonenumber_field.formfields import PhoneNumberField
class ClientForm(forms.Form):
    phone = PhoneNumberField()

Отримати телефон як рядок з об’єктного поля:

    client.phone.as_e164 

Нормалізуйте рядок телефону (для тестів та іншого персоналу):

    from phonenumber_field.phonenumber import PhoneNumber
    phone = PhoneNumber.from_string(phone_number=raw_phone, region='RU').as_e164

2. Телефон за допомогою regexp

Одна примітка до вашої моделі: номери E.164 мають максимум 15 символів.

Для перевірки ви можете скористатися деякою комбінацією форматування, а потім спробувати зв’язатися з номером негайно для підтвердження.

Я вважаю, що я використав щось подібне до свого проекту джанго:

class ReceiverForm(forms.ModelForm):
    phone_number = forms.RegexField(regex=r'^\+?1?\d{9,15}$', 
                                error_message = ("Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed."))

EDIT

Здається, що ця публікація була корисною для деяких людей, і, здається, варто її інтегрувати внизу коментаря в більш повноцінна відповідь. Відповідно до jpotter6 , ви також можете зробити щось подібне на своїх моделях:

models.py:

from django.core.validators import RegexValidator

class PhoneModel(models.Model):
    ...
    phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
    phone_number = models.CharField(validators=[phone_regex], max_length=17, blank=True) # validators should be a list

19
Це може бути цінним показати, як це зробити і на моделі. phone_regex = RegexValidator (regex = r '^ \ +? 1? \ d {9,15} $', message = "Номер телефону потрібно ввести у форматі: '+999999999'. Дозволено до 15 цифр.") = models.CharField (validators = phone_regex, blank = True)
jpotts18

12
Не забудьте додати до моделей 'max_length = 15' .CharField
Естебан

4
@Esteban - max_length = 16 (є необов'язковий + на початку)
dhackner

3
@erewok - Я не вірю, що ти хочеш "1" у твоєму регексе. E.164 дозволяє містити до 15 цифр, включаючи код країни.
dhackner

1
Дійсно, E.164 не містить жодних префіксів міжнародних викликів, лише код країни з наступним фактичним номером, а також мінімальна довжина номера E.164, здається, становить 8, тож регулярний вираз повинен бути, '^\+\d{8,15}$'а потім max_length=16для CharField.
Максим Р.

48

Використовуйте django-phonenumber-field: https://github.com/stefanfoulis/django-phonenumber-field

pip install django-phonenumber-field

1
Не забудьте додати регіон. Без PHONENUMBER_DEFAULT_REGION = 'US'цих налаштувань це не дозволить вам вводити все, що користувачі зі Сполучених Штатів визнали б номером телефону. Навіть тоді цей пакет не виводиться як щось, що схоже на номер телефону. . . Я впевнений, що є параметр, якого я ще не знайшов!
Дриган

7
Примітка: цей пакет дуже великий. Понад 40 Мб. 33 Мб - це геодані.
Прогноз

1
Зауважуючи коментар @Forethinker, набагато легшою альтернативою є github.com/VeryApt/django-phone-field , viapip install django-phone-field
SMX

@Forethinker, тоді ми можемо використовувати "Lite" версію, pip install django-phonenumber-field[phonenumberslite]яка не включає метадані геокодування, носія та часового поясу
heyjr


3

Перевірка проста, введіть їм трохи коду для введення. CharField - прекрасний спосіб його зберігання. Я б не переживав надто про канонізацію номерів телефонів.


1

Все залежить від того, що ви розумієте як номер телефону. Номери телефонів залежать від країни. Пакети місцевих продуктів для кількох країн містять власне "поле номера телефону". Тож якщо вам все одно, що є країною, вам слід ознайомитися з пакетом localflavor (class us.models.PhoneNumberField для випадку США тощо).

В іншому випадку ви можете оглянути місцеві аромати, щоб отримати максимальну довжину для всіх країн. Localflavor також має поля форм, які ви можете використовувати спільно з кодом країни для підтвердження номера телефону.


Гм Так, я виявив це, поки робив дослідження. Чи можете ви навести приклад того, як його використовувати у формі.
pynovice

1

Я опишу, що я використовую:

Перевірка: рядок містить більше 5 цифр.

Очищення: видаливши всі нецифрові символи, запишіть у db лише цифри. Мені пощастило, бо в моїй країні (Росії) всі мають телефонні номери з 10 цифрами. Тому я зберігаю в db лише 10 діт. Якщо ви пишете заявку на багато країн, то вам слід зробити всебічну перевірку.

Візуалізація: я записую власний тег шаблону, щоб добре відобразити його в шаблоні. Або навіть надавати його як зображення - безпечніше запобігти sms-спаму.


0

Інші згадували django-phonenumber-field. Щоб отримати формат відображення , як ви хочете , вам необхідно встановити PHONENUMBER_DEFAULT_FORMATнастройки для "E164", "INTERNATIONAL", "NATIONAL"або "RFC3966"ж ви хочете відображатися на дисплеї. Дивіться джерело GitHub .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.