Jaki jest najlepszy sposób przechowywania numeru telefonu w modelach Django

131

Numer telefonu przechowuję w modelnastępujący sposób:

phone_number = models.CharField(max_length=12)

Użytkownik wprowadziłby numer telefonu, a ja użyłbym numeru telefonu dla SMS AuthenticationTa aplikacja byłaby używana globalnie. Więc potrzebowałbym również kodu kraju. Czy CharFieldto dobry sposób na przechowywanie numeru telefonu? Jak zweryfikować numer telefonu?

pynovice
źródło
1
Jest tu świetna sugestia: stackoverflow.com/a/1245990/207791
Victor Sergienko

Odpowiedzi:

283

W rzeczywistości możesz zajrzeć do znormalizowanego na całym świecie formatu E.164 , zalecanego na przykład przez Twilio (którzy mają usługę i interfejs API do wysyłania wiadomości SMS lub połączeń telefonicznych za pośrednictwem żądań REST).

Jest to prawdopodobnie najbardziej uniwersalny sposób przechowywania numerów telefonów, zwłaszcza jeśli masz numery międzynarodowe.

1. Telefon przez PhoneNumberField

Możesz skorzystać z phonenumber_fieldbiblioteki. Jest to port biblioteki Google libphonenumber, która obsługuje obsługę numerów telefonów Androida https://github.com/stefanfoulis/django-phonenumber-field

W modelu:

from phonenumber_field.modelfields import PhoneNumberField

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

Formalnie:

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

Pobierz telefon jako ciąg z pola obiektu:

    client.phone.as_e164 

Normolize string phone (do testów i innych pracowników):

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

2. Telefon przez regexp

Jedna uwaga dotycząca twojego modelu: numery E.164 mają maksymalną długość 15 znaków.

Aby to sprawdzić, możesz zastosować kombinację formatowania, a następnie spróbować natychmiast skontaktować się z numerem w celu weryfikacji.

Wydaje mi się, że w moim projekcie django użyłem czegoś takiego:

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

EDYTOWAĆ

Wygląda na to, że ten post był przydatny dla niektórych osób i wydaje się, że warto włączyć poniższy komentarz do pełniejszej odpowiedzi. Zgodnie z jpotter6 , możesz również wykonać na swoich modelach coś takiego:

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
źródło
19
Warto też pokazać, jak to zrobić na modelu. phone_regex = RegexValidator (regex = r '^ \ +? 1? \ d {9,15} $', message = "Numer telefonu należy wprowadzić w formacie: '+999999999'. Dozwolone maksymalnie 15 cyfr.") numer_telefonu = modeles.CharField (validators = phone_regex, blank = True)
jpotts18
12
Nie zapomnij dodać do modeli „max_length = 15”. CharField
Esteban
4
@Esteban - max_length = 16 (jest opcjonalny + na początku)
dhackner
3
@erewok - nie wierzę, że chcesz mieć „1” w swoim wyrażeniu regularnym. E.164 dopuszcza maksymalnie 15 cyfr, łącznie z kodem kraju.
dhackner
1
Rzeczywiście, E.164 nie zawiera żadnych prefiksów połączeń międzynarodowych, tylko kod kraju, po którym następuje faktyczny numer, również minimalna długość numeru E.164 wydaje się wynosić 8, więc wyrażenie regularne powinno wynosić, '^\+\d{8,15}$'a następnie max_length=16dla CharField.
Maxime R.
48

Użyj pola django-phonenumber-field: https://github.com/stefanfoulis/django-phonenumber-field

pip install django-phonenumber-field
rgenito
źródło
1
Nie zapomnij dodać regionu. Bez PHONENUMBER_DEFAULT_REGION = 'US'tych ustawień nie będzie można wprowadzić niczego, co użytkownicy ze Stanów Zjednoczonych rozpoznaliby jako numer telefonu. Nawet wtedy ten pakiet nie zostanie wyświetlony jako coś, co wygląda jak numer telefonu. . . Jestem pewien, że istnieje ustawienie, którego jeszcze nie znalazłem!
Drigan,
7
Uwaga: ten pakiet jest bardzo duży. Ponad 40 MB. 33 MB z tego to dane geograficzne.
Forethinker
1
Odnotowując komentarz @Forethinker, znacznie lżejszą alternatywą jest github.com/VeryApt/django-phone-field , viapip install django-phone-field
SMX
@Forethinker wtedy możemy użyć wersji „lite”, pip install django-phonenumber-field[phonenumberslite]która nie zawiera metadanych geokodowania, nośnika i strefy czasowej
heyjr
3

Walidacja jest łatwa, napisz im mały kod do wpisania. CharField to świetny sposób na jego przechowywanie. Nie martwiłbym się zbytnio kanonizacją numerów telefonów.

U2EF1
źródło
1

Wszystko zależy od tego, co rozumiesz jako numer telefonu. Numery telefonów zależą od kraju. Pakiety lokalnych smaków dla kilku krajów zawierają własne „pole numeru telefonu”. Więc jeśli nie przeszkadza ci, jeśli chodzi o określony kraj, powinieneś spojrzeć na pakiet lokalnych smaków (class us.models.PhoneNumberField w przypadku USA itp.)

W przeciwnym razie możesz sprawdzić lokalne smaki, aby uzyskać maksymalną długość dla wszystkich krajów. Localflavor ma również pola formularzy, których możesz użyć w połączeniu z kodem kraju, aby zweryfikować numer telefonu.

esauro
źródło
Hm Tak, odkryłem to podczas zbierania informacji. Czy możesz podać przykład, jak go używać w formularzu.
pynovice
1

Opiszę czego używam:

Walidacja: ciąg zawiera więcej niż 5 cyfr.

Czyszczenie: usuwanie wszystkich symboli innych niż cyfry, wpisywanie tylko liczb w db. Mam szczęście, bo w moim kraju (Rosja) każdy ma 10-cyfrowe numery telefonów. Więc przechowuję w db tylko 10 diits. Jeśli piszesz wniosek obejmujący wiele krajów, powinieneś dokonać kompleksowej weryfikacji.

Renderowanie: piszę niestandardowy tag szablonu, aby ładnie renderować go w szablonie. Lub nawet wyrenderuj go jak obrazek - bezpieczniej jest zapobiegać spamowaniu przez sms.

Павел Тявин
źródło
0

Inni wspomnieli django-phonenumber-field. Aby uzyskać format wyświetlania jak chcesz trzeba ustawić PHONENUMBER_DEFAULT_FORMATustawienia do "E164", "INTERNATIONAL", "NATIONAL", lub "RFC3966", jednak chcesz to wyświetlany. Zobacz źródło GitHub .

GoPackGo90
źródło