Qual é a melhor maneira de armazenar número de telefone nos modelos do Django

131

Estou armazenando um número de telefone modelassim:

phone_number = models.CharField(max_length=12)

O usuário digitaria um número de telefone e eu usaria o número de telefone para SMS AuthenticationEste aplicativo seria usado globalmente. Então, eu também precisaria do código do país. É CharFielduma boa maneira de armazenar o número de telefone? E como validar o número de telefone?

pynovice
fonte
1
Há uma grande sugestão aqui: stackoverflow.com/a/1245990/207791
Victor Sergienko

Respostas:

283

Você pode realmente procurar o formato internacionalmente padronizado E.164 , recomendado pelo Twilio, por exemplo (que possui um serviço e uma API para enviar SMS ou telefonemas através de solicitações REST).

É provável que seja a maneira mais universal de armazenar números de telefone, principalmente se você trabalha com números internacionais.

1. Telefone por PhoneNumberField

Você pode usar a phonenumber_fieldbiblioteca. É o porto da biblioteca libphonenumber do Google, que possibilita o processamento de números de telefone do Android https://github.com/stefanfoulis/django-phonenumber-field

No modelo:

from phonenumber_field.modelfields import PhoneNumberField

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

No formulário:

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

Obter telefone como string do campo de objeto:

    client.phone.as_e164 

Normolize a sequência telefônica (para testes e outras equipes):

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

2. Telefone por regexp

Uma observação para o seu modelo: os números E.164 têm um comprimento máximo de 15 caracteres.

Para validar, você pode empregar alguma combinação de formatação e tentar entrar em contato com o número imediatamente para verificar.

Acredito que usei algo como o seguinte no meu projeto 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."))

EDITAR

Parece que este post foi útil para algumas pessoas, e parece valer a pena integrar o comentário abaixo em uma resposta mais completa. De acordo com o jpotter6 , você também pode fazer o seguinte em seus modelos:

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
fonte
19
Pode ser valioso mostrar como fazer isso também em um modelo. phone_regex = RegexValidator (regex = r '^ \ +? 1? \ d {9,15} $', message = "O número de telefone deve ser digitado no formato: '+999999999'. Até 15 dígitos permitidos.") phone_number = models.CharField (validators = phone_regex, blank = True)
jpotts18
12
Não esqueça de adicionar 'max_length = 15' aos modelos
Esteban
4
@Esteban - max_length = 16 (há um opcional + no início)
dhackner
3
@erewok - Não acredito que você queira o '1' no seu regex. O E.164 permite até 15 dígitos, inclusive o código do país.
Dhckner
1
De fato, o E.164 não inclui nenhum prefixo de chamada internacional; apenas o código do país seguido pelo número real; também o comprimento mínimo de um número E.164 parece ser 8; portanto, o regex deve ser '^\+\d{8,15}$'e, max_length=16em seguida, para o CharField.
Maxime R.
48

Use django-phonenumber-field: https://github.com/stefanfoulis/django-phonenumber-field

pip install django-phonenumber-field
rgenito
fonte
1
Não se esqueça de adicionar a região. Sem PHONENUMBER_DEFAULT_REGION = 'US'as configurações, não permitirá que você insira nada que os usuários dos Estados Unidos reconheçam como um número de telefone. Mesmo assim, este pacote não será exibido como um número de telefone. . . Tenho certeza de que há uma configuração que ainda não encontrei!
Drigan
7
Nota: este pacote é muito grande. Mais de 40MB. 33 MB são dados geográficos.
Forethinker 18/09/18
1
Observando o comentário do @Forethinker, uma alternativa muito mais leve é ​​o github.com/VeryApt/django-phone-field , viapip install django-phone-field
SMX
@Forethinker, podemos usar a versão "lite", pip install django-phonenumber-field[phonenumberslite]que não inclui os metadados de geocodificação, operadora e fuso horário
heyjr
3

A validação é fácil, digite um pequeno código para digitar. Um CharField é uma ótima maneira de armazená-lo. Eu não me preocuparia muito em canonizar números de telefone.

U2EF1
fonte
1

Tudo depende do que você entende como número de telefone. Os números de telefone são específicos do país. Os pacotes sabores locais para vários países contêm seu próprio "campo de número de telefone". Portanto, se você está bem, sendo específico do país, consulte o pacote de sabores locais ( class us.models.PhoneNumberFieldno caso dos EUA, etc.)

Caso contrário, você pode inspecionar os sabores locais para obter o comprimento máximo para todos os países. O Localflavor também possui campos de formulários que você pode usar em conjunto com o código do país para validar o número de telefone.

esauro
fonte
Hum, eu descobri isso enquanto fazia uma pesquisa. Você pode dar um exemplo de como usá-lo em um formulário.
Pynovice #
1

Vou descrever o que eu uso:

Validação: string contém mais de 5 dígitos.

Limpeza: removendo todos os símbolos que não sejam dígitos, escreva apenas em números db. Tenho sorte, porque no meu país (Rússia) todo mundo tem números de telefone com 10 dígitos. Então eu guardo no db apenas 10 diits. Se você estiver escrevendo um aplicativo para vários países, faça uma validação abrangente.

Renderização: escrevo uma tag de modelo personalizada para renderizá-la perfeitamente no modelo. Ou até mesmo renderizá-lo como uma imagem - é mais seguro evitar spam sms.

Павел Тявин
fonte
0

Outros mencionados django-phonenumber-field. Para obter o formato de exibição como você quer você precisa definir PHONENUMBER_DEFAULT_FORMATconfiguração para "E164", "INTERNATIONAL", "NATIONAL"ou "RFC3966", no entanto você quer que ele exibida. Veja a fonte do GitHub .

GoPackGo90
fonte