Quelle est la meilleure façon de stocker un numéro de téléphone dans les modèles Django

131

Je stocke un numéro de téléphone modelcomme ceci:

phone_number = models.CharField(max_length=12)

L'utilisateur entrerait un numéro de téléphone et j'utiliserais le numéro de téléphone pour SMS AuthenticationCette application serait utilisée dans le monde entier. J'aurais donc également besoin d'un code de pays. Est-ce CharFieldun bon moyen de stocker un numéro de téléphone? Et comment valider le numéro de téléphone?

pynovice
la source
1
Il y a une excellente suggestion ici: stackoverflow.com/a/1245990/207791
Victor Sergienko

Réponses:

283

Vous pouvez en fait regarder dans le format normalisé internationalement E.164 , recommandé par Twilio par exemple (qui ont un service et une API pour envoyer des SMS ou des appels téléphoniques via des requêtes REST).

C'est probablement le moyen le plus universel de stocker des numéros de téléphone, en particulier si vous travaillez avec des numéros internationaux.

1. Téléphone par PhoneNumberField

Vous pouvez utiliser la phonenumber_fieldbibliothèque. C'est le port de la bibliothèque libphonenumber de Google, qui alimente la gestion des numéros de téléphone d'Android https://github.com/stefanfoulis/django-phonenumber-field

Dans le modèle:

from phonenumber_field.modelfields import PhoneNumberField

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

Informer:

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

Obtenez le téléphone sous forme de chaîne à partir du champ objet:

    client.phone.as_e164 

Normoliser la chaîne téléphonique (pour les tests et autres membres du personnel):

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

2. Téléphone par regexp

Une note pour votre modèle: les nombres E.164 ont une longueur maximale de 15 caractères.

Pour valider, vous pouvez utiliser une combinaison de formatage, puis tenter de contacter immédiatement le numéro pour vérifier.

Je crois que j'ai utilisé quelque chose comme ce qui suit sur mon projet 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."))

ÉDITER

Il semble que cet article ait été utile à certaines personnes, et il semble intéressant d'intégrer le commentaire ci-dessous dans une réponse plus complète. Selon jpotter6 , vous pouvez également faire quelque chose comme ce qui suit sur vos modèles:

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
la source
19
Il peut être utile de montrer également comment procéder sur un modèle. phone_regex = RegexValidator (regex = r '^ \ +? 1? \ d {9,15} $', message = "Le numéro de téléphone doit être saisi au format: '+999999999'. Jusqu'à 15 chiffres autorisés.") phone_number = models.CharField (validators = phone_regex, blank = True)
jpotts18
12
N'oubliez pas d'ajouter 'max_length = 15' aux modèles.CharField
Esteban
4
@Esteban - max_length = 16 (il y a un + optionnel au début)
dhackner
3
@erewok - Je ne crois pas que vous vouliez le «1» dans votre regex. E.164 autorise jusqu'à 15 chiffres, y compris l'indicatif du pays.
dhackner
1
En effet, E.164 n'inclut aucun préfixe d'appel international, seulement l'indicatif de pays suivi du numéro réel, la longueur minimale d'un numéro E.164 semble également être 8, donc l'expression régulière devrait être '^\+\d{8,15}$'et ensuite max_length=16pour le CharField.
Maxime R.
48

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

pip install django-phonenumber-field
rgenito
la source
1
N'oubliez pas d'ajouter la région. Sans PHONENUMBER_DEFAULT_REGION = 'US'les paramètres, il ne vous permettra pas de saisir quoi que ce soit que les utilisateurs des États-Unis reconnaissent comme un numéro de téléphone. Même dans ce cas, ce package ne sera pas généré comme quelque chose qui ressemble à un numéro de téléphone. . . Je suis sûr qu'il y a un paramètre que je n'ai pas encore trouvé!
Drigan
7
Remarque: ce paquet est très volumineux. Plus de 40 Mo. 33 Mo sont des géodonnées.
Forethinker
1
En prenant note du commentaire de @Forethinker, une alternative beaucoup plus légère est github.com/VeryApt/django-phone-field , viapip install django-phone-field
SMX
@Forethinker alors nous pouvons utiliser la version "allégée" pip install django-phonenumber-field[phonenumberslite]qui n'inclut pas les métadonnées de géocodage, de porteuse et de fuseau horaire
heyjr
3

La validation est facile, envoyez-leur un petit code pour les saisir. Un CharField est un excellent moyen de le stocker. Je ne m'inquiéterais pas trop de la canonisation des numéros de téléphone.

U2EF1
la source
1

Tout dépend de ce que vous entendez par numéro de téléphone. Les numéros de téléphone sont spécifiques au pays. Les packages localflavors pour plusieurs pays contiennent leur propre "champ de numéro de téléphone". Donc, si vous êtes d'accord pour être spécifique à un pays, vous devriez jeter un coup d'œil au package localflavor ( class us.models.PhoneNumberFieldpour le cas américain, etc.)

Sinon, vous pouvez inspecter les saveurs locales pour obtenir la longueur maximale pour tous les pays. Localflavor a également des champs de formulaire que vous pouvez utiliser en conjonction avec le code du pays pour valider le numéro de téléphone.

esauro
la source
Hm Oui, j'ai trouvé cela pendant que je faisais une recherche. Pouvez-vous donner un exemple sur la façon de l'utiliser dans un formulaire.
pynovice
1

Je décrirai ce que j'utilise:

Validation: la chaîne contient plus de 5 chiffres.

Nettoyage: en supprimant tous les symboles non numériques, n'écrivez que des nombres en db. J'ai de la chance, car dans mon pays (Russie), tout le monde a des numéros de téléphone à 10 chiffres. Donc je stocke en db seulement 10 diits. Si vous rédigez une candidature multi-pays, vous devez effectuer une validation complète.

Rendu: j'écris une balise de modèle personnalisée pour la rendre joliment dans le modèle. Ou même le rendre comme une image - il est plus sûr d'éviter le spam par SMS.

Павел Тявин
la source
0

D'autres ont mentionné django-phonenumber-field. Pour obtenir le format d'affichage que vous voulez , vous devez définir PHONENUMBER_DEFAULT_FORMATparamètre pour "E164", "INTERNATIONAL", "NATIONAL"ou "RFC3966", mais vous voulez afficher. Voir la source GitHub .

GoPackGo90
la source