¿Cuál es la mejor manera de almacenar el número de teléfono en los modelos Django?

131

Estoy almacenando un número de teléfono modelcomo este:

phone_number = models.CharField(max_length=12)

El usuario ingresaría un número de teléfono y yo usaría el número de teléfono para SMS AuthenticationEsta aplicación se usaría globalmente. Entonces también necesitaría el código del país. ¿Es CharFielduna buena manera de almacenar el número de teléfono? ¿Y cómo valido el número de teléfono?

pynovice
fuente
1
Aquí hay una gran sugerencia: stackoverflow.com/a/1245990/207791
Victor Sergienko

Respuestas:

283

En realidad, puede buscar el formato E.164 estandarizado internacionalmente , recomendado por Twilio por ejemplo (que tiene un servicio y una API para enviar SMS o llamadas telefónicas a través de solicitudes REST).

Es probable que esta sea la forma más universal de almacenar números de teléfono, en particular si tiene números internacionales con los que trabajar.

1. Teléfono por teléfonoNumberField

Puedes usar la phonenumber_fieldbiblioteca. Es el puerto de la biblioteca libphonenumber de Google, que impulsa el manejo del número de teléfono de Android https://github.com/stefanfoulis/django-phonenumber-field

En modelo:

from phonenumber_field.modelfields import PhoneNumberField

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

En forma:

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

Obtener el teléfono como una cadena del campo de objeto:

    client.phone.as_e164 

Normolize cadena telefónica (para pruebas y otro personal):

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

2. Teléfono por regexp

Una nota para su modelo: los números E.164 tienen una longitud máxima de 15 caracteres.

Para validar, puede emplear alguna combinación de formato y luego intentar contactar el número inmediatamente para verificar.

Creo que usé algo como lo siguiente en mi proyecto 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 esta publicación ha sido útil para algunas personas, y parece que vale la pena integrar el comentario a continuación en una respuesta más completa. Según jpotter6 , también puede hacer algo como lo siguiente en sus modelos:

modelos.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
fuente
19
Puede ser valioso mostrar cómo hacer esto también en un modelo. phone_regex = RegexValidator (regex = r '^ \ +? 1? \ d {9,15} $', mensaje = "El número de teléfono debe ingresarse en el formato: '+999999999'. Se permiten hasta 15 dígitos".) número_de_teléfono = models.CharField (validators = phone_regex, blank = True)
jpotts18
12
No olvides agregar 'max_length = 15' a los modelos
Esteban
44
@Esteban - max_length = 16 (hay un + opcional al inicio)
dhackner
3
@erewok - No creo que quieras el '1' en tu expresión regular. E.164 admite hasta 15 dígitos, incluido el código del país.
dhackner
1
De hecho, E.164 no incluye ningún prefijo de llamada internacional, solo el código del país seguido del número real, también la longitud mínima de un número E.164 parece ser 8, por lo que la expresión regular debería ser '^\+\d{8,15}$'y luego max_length=16para el CharField.
Maxime R.
48

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

pip install django-phonenumber-field
rgenito
fuente
1
No olvides agregar la región. Sin PHONENUMBER_DEFAULT_REGION = 'US'la configuración, no le permitirá ingresar nada que los usuarios de los Estados Unidos reconozcan como un número de teléfono. Incluso entonces, este paquete no saldrá como algo que parece un número de teléfono. . . ¡Estoy seguro de que hay una configuración que todavía no he encontrado!
Drigan
77
Nota: este paquete es muy grande. Más de 40 MB. 33MB son geodatos.
Forethinker
1
Tomando nota del comentario de @Forethinker, una alternativa mucho más ligera es github.com/VeryApt/django-phone-field , a través depip install django-phone-field
SMX
@Forethinker, entonces podemos usar la versión "lite" pip install django-phonenumber-field[phonenumberslite]que no incluye los metadatos de geocodificación, portador y zona horaria
heyjr
3

La validación es fácil, envíeles un pequeño código de texto para escribir. Un CharField es una excelente manera de almacenarlo. No me preocuparía demasiado por canonizar los números de teléfono.

U2EF1
fuente
1

Todo depende de lo que entiendas como número de teléfono. Los números de teléfono son específicos del país. Los paquetes de sabores locales para varios países contienen su propio "campo de número de teléfono". Entonces, si está de acuerdo en ser específico del país, debe echar un vistazo al paquete de sabor local ( class us.models.PhoneNumberFieldpara el caso de EE. UU., Etc.)

De lo contrario, podría inspeccionar los sabores locales para obtener la longitud máxima para todos los países. Localflavor también tiene campos de formularios que puede usar junto con el código del país para validar el número de teléfono.

esauro
fuente
Hm Sí, lo descubrí mientras investigaba. ¿Puedes dar un ejemplo de cómo usarlo en un formulario?
pynovice
1

Describiré lo que uso:

Validación: la cadena contiene más de 5 dígitos.

Limpieza: elimina todos los símbolos que no sean dígitos, escriba solo números db. Tengo suerte, porque en mi país (Rusia) todos tienen números de teléfono con 10 dígitos. Así que guardo en db solo 10 diits. Si está escribiendo una aplicación para varios países, debe realizar una validación completa.

Representación: escribo una etiqueta de plantilla personalizada para representarla en la plantilla de forma agradable. O incluso renderizarlo como una imagen: es más seguro evitar el spam de sms.

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

Otros mencionados django-phonenumber-field. Para obtener el formato de visualización de cómo desea que necesita para configurar PHONENUMBER_DEFAULT_FORMATajuste para "E164", "INTERNATIONAL", "NATIONAL", o "RFC3966", como quiera que se muestre. Ver la fuente de GitHub .

GoPackGo90
fuente