Как лучше всего хранить номер телефона в моделях Django

132

Я храню номер телефона modelтак:

phone_number = models.CharField(max_length=12)

Пользователь должен ввести номер телефона, и я буду использовать этот номер телефона, чтобы SMS Authenticationэто приложение использовалось глобально. Так что мне также понадобится код страны. Есть CharFieldхороший способ сохранить номер телефона? И как мне подтвердить номер телефона?

pynovice
источник
1
Здесь есть отличное предложение: stackoverflow.com/a/1245990/207791
Виктор Сергиенко

Ответы:

286

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

Это, вероятно, будет наиболее универсальным способом хранения телефонных номеров, особенно если у вас есть международные номера.

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

Вы можете использовать phonenumber_fieldбиблиотеку. Это порт библиотеки libphonenumber от Google, которая обеспечивает обработку телефонных номеров 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. Телефон с помощью регулярного выражения

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

Для проверки вы можете использовать некоторую комбинацию форматирования, а затем немедленно попытаться связаться с номером для проверки.

Я считаю, что в своем проекте django использовал что-то вроде следующего:

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."))

РЕДАКТИРОВАТЬ

Похоже, что этот пост был полезен для некоторых людей, и кажется, что стоит интегрировать комментарий ниже в более полноценный ответ. Согласно 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
erewok
источник
19
Было бы полезно показать, как это сделать и на модели. phone_regex = RegexValidator (regex = r '^ \ +? 1? \ d {9,15} $', message = "Номер телефона необходимо вводить в формате: '+999999999'. Допускается до 15 цифр.") phone_number = 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 03 фев.15,
1
Действительно, E.164 не включает никаких префиксов международных вызовов, только код страны, за которым следует фактический номер, также минимальная длина номера E.164 кажется равной 8, поэтому должно быть регулярное выражение, '^\+\d{8,15}$'а затем max_length=16для CharField.
Максим Р.
49

Используйте поле django-phonenumber-field: https://github.com/stefanfoulis/django-phonenumber-field

pip install django-phonenumber-field
rgenito
источник
1
Не забудьте добавить регион. Без PHONENUMBER_DEFAULT_REGION = 'US'настроек он не позволит вам вводить что-либо, что пользователи из США распознают как номер телефона. Даже в этом случае этот пакет не будет выводиться как нечто похожее на номер телефона. , , Я уверен, что есть настройка, которую я еще не нашел!
Drigan
7
Примечание: этот пакет очень большой. Более 40 МБ. 33 МБ из них - геоданные.
Forethinker
1
Отмечая комментарий @Forethinker, гораздо более легкая альтернатива - github.com/VeryApt/django-phone-field , черезpip install django-phone-field
SMX
@Forethinker, тогда мы можем использовать "облегченную" версию, pip install django-phonenumber-field[phonenumberslite]которая не включает метаданные геокодирования, оператора связи и часового пояса
heyjr
3

Проверка проста, напишите им небольшой код для ввода. CharField - отличный способ его сохранить. Я бы не стал слишком беспокоиться о канонизации телефонных номеров.

U2EF1
источник
1

Все зависит от того, что вы понимаете под номером телефона. Номера телефонов зависят от страны. Пакеты localflavors для нескольких стран содержат собственное «поле номера телефона». Так что, если вас устраивает конкретная страна, вам следует взглянуть на пакет localflavor ( class us.models.PhoneNumberFieldдля случая США и т. Д.)

В противном случае вы могли бы изучить местные вкусы, чтобы получить максимальную длину для всех стран. Localflavor также имеет поля форм, которые вы можете использовать вместе с кодом страны для проверки номера телефона.

esauro
источник
Хм Да, я обнаружил это, когда проводил исследование. Вы можете привести пример того, как его использовать в форме.
pynovice 02
1

Опишу, что использую:

Проверка: строка содержит более 5 цифр.

Очистка: удаление всех нецифровых символов, запись в БД только цифр. Мне повезло, потому что в моей стране (России) у всех есть 10-значные телефонные номера. Так что я храню в db только 10 диитов. Если вы пишете заявку для нескольких стран, вам следует провести всестороннюю проверку.

Рендеринг: я пишу собственный тег шаблона, чтобы он красиво отображался в шаблоне. Или даже визуализировать его как картинку - так безопаснее предотвратить смс-спам.

Павел Тявин
источник
0

Упомянутые другие django-phonenumber-field. Чтобы получить формат отображения , как вы хотите , вам необходимо установить PHONENUMBER_DEFAULT_FORMATнастройки для "E164", "INTERNATIONAL", "NATIONAL"или "RFC3966"же вы хотите отображаться на дисплее. См. Исходный код на GitHub .

GoPackGo90
источник