Maison  >  Article  >  développement back-end  >  Application de gestion de comptes Django (inscription et activation

Application de gestion de comptes Django (inscription et activation

Patricia Arquette
Patricia Arquetteoriginal
2024-11-04 21:57:02971parcourir

Qu’attendre de cet article ?

Nous avons créé la structure du projet dans l'article précédent, cet article s'appuiera sur elle. ça couvrira

  • Structure de la base de données des comptes, y compris les utilisateurs et le code de vérification.
  • Modèles sérialiseurs.
  • Vues du compte pour l'enregistrement et l'activation du compte. le prochain article devrait couvrir le reste des points de vue, tels que la connexion, l'actualisation des jetons, la modification du mot de passe, l'oubli du mot de passe et le renvoi du code.

Je vais essayer de couvrir autant de détails que possible sans vous ennuyer, mais j'attends quand même que vous soyez familier avec certains aspects de Python et Django.

la version finale du code source est disponible sur https://github.com/saad4software/alive-diary-backend

Ordre de série

Consultez les articles précédents si vous êtes intéressé !

  1. Projet IA à partir de zéro, The Idea, Alive Diary
  2. Prouvez que c'est faisable avec Google AI Studio
  3. Configuration du projet API Django
  4. Application de gestion de comptes Django (1), inscription et activation (Vous êtes ici ?)

Configuration de l'application Comptes

créons un fichier de sérialiseurs dans l'application

from rest_framework import serializers
from app_account.models import *

app_account/serializers.py

et le fichier urls

from django.urls import path, include
from .views import *

urlpatterns = [

]

app_account/urls.py

Enfin, connectons les URL de l'application aux URL du projet en éditant le fichier d'URL du projet comme

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

alive_diary/urls.py

Nous pouvons désormais appeler n'importe quelle URL de compte avec le préfixe "api/account/"

Les modèles

le modèle principal pour l'application de comptes est bien sûr le modèle utilisateur

from django.db import models
from django.contrib.auth.models import AbstractUser
from datetime import timedelta, datetime

class User(AbstractUser):
    userTypes = (
        ('A', 'Admin'),
        ('C', 'Client'),
    )

    role = models.CharField(max_length=1, choices=userTypes, default="C")

    hobbies = models.CharField(max_length=255, null=True, blank=True)
    job = models.CharField(max_length=100, null=True, blank=True)
    bio = models.TextField(null=True, blank=True)

    country_code = models.CharField(max_length=10, null=True, blank=True)
    expiration_date = models.DateTimeField(default=datetime.now()+timedelta(days=30))

app_account/models.py

Habituellement, il est préférable de garder le modèle utilisateur aussi simple que possible et de déplacer les autres détails vers un modèle de profil avec une relation individuelle avec l'utilisateur, mais pour simplifier les choses, j'ajouterai les informations utilisateur requises. directement au modèle utilisateur cette fois.

Nous héritons du modèle AbstractUser, AbstractUser inclut plusieurs champs

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(...)
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    email = models.EmailField(...)
    is_staff = models.BooleanField(...)
    is_active = models.BooleanField(...),
    date_joined = models.DateTimeField(...)

les plus importants sont :

  • le nom d'utilisateur sera utilisé pour se connecter.
  • is_active sera utilisé pour empêcher les comptes non vérifiés de se connecter.
  • is_staff distinguera l'administrateur (avec la valeur true) des utilisateurs normaux.

Nous avons également ajouté plusieurs champs pour cet utilisateur du projet qui sont

  • rôle pour distinguer l'administrateur des comptes clients, nous pouvons utiliser is_staff pour ce projet simple puisque nous n'avons que deux rôles, mais un projet plus vaste peut avoir plus de 2 rôles, ce qui rend ce champ essentiel pour la gestion des autorisations.
  • loisirs, travail, biographie En savoir plus sur l'utilisateur peut aider à construire une meilleure réflexion, c'est pourquoi nous demandons des passe-temps, un travail et la façon dont l'utilisateur se décrit.
  • country_code pour les statistiques
  • expiration_date pour la date d'expiration basée sur l'abonnement.

Nous avons également besoin d'un modèle de code de vérification pour conserver et suivre les codes de vérification pour l'activation du compte, l'oubli des mots de passe et le renvoi des codes.

from rest_framework import serializers
from app_account.models import *

app_account/models.py

Il se connecte au modèle utilisateur et génère une valeur aléatoire d'un numéro de code à 6 chiffres. il a également un délai d’expiration de 24 heures. nous avons également un courrier électronique déposé au cas où l'utilisateur souhaite valider plusieurs adresses e-mail, c'est rare et peut être supprimé pour cette application. Passons ensuite aux sérialiseurs.

L'API d'inscription

commençons par le sérialiseur

from django.urls import path, include
from .views import *

urlpatterns = [

]

app_account/serializers.py

Nous utilisons ModelSerializer, du framework rest Django. nous avons sélectionné le modèle utilisateur get_user_model() dans la classe Meta et une liste de champs sérialisés.

Nous avons ajouté deux champs supplémentaires au sérialiseur de modèle, password1 et password2. Pour valider qu'ils ont la même valeur, nous avons écrasé la méthode validate. et pour imposer l'utilisation d'une adresse e-mail valide comme nom d'utilisateur, nous avons ajouté un validateur de champ pour le champ de nom d'utilisateur.
la fonction is_valid_email devrait ressembler un peu à ceci

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

common/utils.py

Personnellement, je n'aime pas les expressions régulières, je ne les ai jamais comprises, mais elles semblent être le meilleur moyen de valider les emails. Si vous avez un meilleur moyen, partagez-le avec nous.

Comme nos nouveaux champs password1 et password2 n'appartiennent pas au modèle utilisateur d'origine, nous les avons supprimés du dictionnaire de données et ajouté le champ mot de passe afin d'utiliser directement les données du sérialiseur pour créer un nouvel utilisateur.

Le dilemme des meilleures pratiques du sérialiseur

  • Les sérialiseurs devraient-ils utiliser des requêtes de base de données et modifier des bases de données ?
  • ou devraient-ils uniquement effectuer une validation de type de champ de base (chaîne, entier, ...) ?

Il n'y a pas de réponse claire en fait, par exemple, les sérialiseurs du modèle de framework Django Rest semblent faire des requêtes pour des champs uniques, comme l'erreur du sérialiseur que nous avons eue lorsque nous avons essayé de créer une utilisation avec le même nom, elle a été générée par le sérialiseur, pas la vue.
Les méthodes Create, Save, Update écrivent les valeurs dans la base de données.
Pourtant, accéder à la base de données uniquement dans les vues semble correspondre davantage à la Séparation des préoccupations et à la Flexibilité.

Qu'est-ce qui est mieux selon vous ?

J'ai beaucoup lu sur la nécessité de séparer les choses, voire de séparer les requêtes de base de données des méthodes de mise à jour de la base de données. alors essayons de faire ça. la création de AccountActivateView dans le fichier views.py devrait ressembler à cela.

Dans notre cas, nous pouvons écraser la méthode create pour RegisterSerializer afin de créer un nouvel utilisateur et des instants de code de validation, et même envoyer le code de vérification depuis le sérialiseur.

Mais à la place, je conserverai les opérations liées au modèle dans le fichier de vues

Passons à la vue d'inscription

from rest_framework import serializers
from app_account.models import *

app_account/views.py

Nous utilisons CreatAPIView à partir du reste du framework, il accepte les requêtes POST avec le schéma de serializer_class, le BrowsableAPIRenderer construit une interface Web pour cette API et le JSONRenderer est responsable de la construction de la réponse JSON.

L'écrasement de la méthode perform_create nous permet de contrôler le mécanisme de création d'utilisateur, nous créons l'instant utilisateur, nous assurons que le champ is_active est défini sur False, puis créons l'instantané de code de vérification qui est connecté au nouveau modèle utilisateur, et enfin envoyons un e-mail avec le code de vérification à l'utilisateur.

L'envoi de l'e-mail nécessite la configuration correcte des champs d'e-mail dans le fichier de configuration, veuillez me faire savoir si vous rencontrez des problèmes sur ce point particulier pour créer un article séparé pour cela

Enfin, ajoutons l'url de l'API

from django.urls import path, include
from .views import *

urlpatterns = [

]

app_account/urls.py

Bien, essayons-le

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

en ouvrant http://localhost:8555/api/account/register, nous devrions pouvoir voir quelque chose comme ça (c'est dû à BrowsableAPIRenderer)

Django accounts management app ( registration and activation

les champs obligatoires sont le nom d'utilisateur, le mot de passe1 et le mot de passe2, nous nous attendons à ce que l'e-mail soit utilisé comme nom d'utilisateur.
ça a l'air bien, il a créé un modèle utilisateur avec un modèle de code de vérification qui y est connecté (utilisé SqlBrowser pour ouvrir le fichier de base de données SQLite). Mais la réponse par défaut ressemble à ceci avec le statut 201.

from django.db import models
from django.contrib.auth.models import AbstractUser
from datetime import timedelta, datetime

class User(AbstractUser):
    userTypes = (
        ('A', 'Admin'),
        ('C', 'Client'),
    )

    role = models.CharField(max_length=1, choices=userTypes, default="C")

    hobbies = models.CharField(max_length=255, null=True, blank=True)
    job = models.CharField(max_length=100, null=True, blank=True)
    bio = models.TextField(null=True, blank=True)

    country_code = models.CharField(max_length=10, null=True, blank=True)
    expiration_date = models.DateTimeField(default=datetime.now()+timedelta(days=30))

Je préfère que toutes les réponses aient ce schéma

class AbstractUser(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(...)
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    email = models.EmailField(...)
    is_staff = models.BooleanField(...)
    is_active = models.BooleanField(...),
    date_joined = models.DateTimeField(...)

  • le statut doit être soit "succès" soit "erreur"
  • code est le code d'état de la réponse
  • les données sont les données de réponse réelles
  • le message doit contenir un texte d'erreur ou tout autre message

Mais comment faire ?
La meilleure façon est d'implémenter une fonction JSON renderer personnalisée. faisons-le

import random

class VerificationCode(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    code = models.CharField(max_length=6, default=random.randint(111111, 999999))
    email = models.EmailField()
    expiration_date = models.DateTimeField(default=datetime.now()+timedelta(days=1))

    def __str__(self):
        return self.user.username

common/utils.py

Nous avons hérité de JSONRenderer et écrasé la méthode de rendu. erreurs du sérialiseur.

  • commencé par lire le code d'état de la réponse et le mettre dans le champ de code
  • et nous avons déplacé les données de réponse réelles vers le champ de données de notre schéma de réponse
  • pour distinguer les erreurs des réponses réussies, nous vérifions le code d'état. Si le code d'état est dans la famille 200, c'est une réponse réussie
  • sinon, c'est une erreur. nous changeons donc le statut en "erreur" et extrayons le message d'erreur du champ des détails de la réponse (si disponible).
  • Les erreurs de validation du sérialiseur n'ont pas de champs de détails, c'est un dictionnaire indiquant un message d'erreur (valeur) pour chaque nom de champ (clé), nous avons donc créé une petite fonction dict2string pour le convertir en une simple chaîne. Je pense que cela peut être encore amélioré, pouvez-vous nous aider ?

C'est tout pour le schéma de réponse, essayons de l'utiliser maintenant !
dans vues.py, ajoutez notre moteur de rendu personnalisé à la classe de vue de registre

from rest_framework import serializers
from app_account.models import *

app_account/views.py

exécuter le serveur et ouvrir http://localhost:8555/api/account/register/ montre directement la différence

Django accounts management app ( registration and activation

on peut voir notre schéma dans le message d'erreur ?, cool, essayons d'enregistrer un nouvel utilisateur, je l'appellerai "test5@gmail.com"

Django accounts management app ( registration and activation

ça a l'air bien, testons maintenant l'erreur de validation du sérialiseur, nous allons essayer d'enregistrer à nouveau le même utilisateur

Django accounts management app ( registration and activation

Merveilleux, c'est une réponse d'erreur de validation, elle a été sérialisée sous forme de champ : message
que se passe-t-il après l'inscription ? c'est une validation
inscrivez-vous -> confirmer l'e-mail -> connexion -> peu importe

L'API d'activation

Nous voulons vérifier si l'utilisateur a reçu ou non le code d'activation que nous avons envoyé lors de l'inscription, si l'utilisateur envoie le bon code, nous activerons son compte, sinon, nous lui demanderons de le vérifier à nouveau, ou peut-être renvoyer le code (une autre API pour plus tard)
Semblable au processus de création de l'API d'enregistrement, commençons par le sérialiseur

from django.urls import path, include
from .views import *

urlpatterns = [

]

Ceci n'est pas lié à un certain modèle de base de données, nous héritons donc du Serializer générique, notez que les sérialiseurs sont similaires aux formulaires, nous définissons donc les champs et leurs règles de validation.
Nous utilisons deux champs de chaîne (CharField), les deux sont obligatoires, le nom d'utilisateur qui est l'adresse e-mail de l'utilisateur et le code.

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

app_account/views.py

Comme nous utilisons une vue API personnalisée, nous héritons d'APIView, elle propose 5 fonctions (get, post, put, delete et patch). Nous désérialisons les données de requête des requêtes POST, validons leur type, puis effectuons une requête pour savoir si les données fournies existent ou non, si elles existent, nous activons l'utilisateur et supprimons l'objet code de sa table. sinon, nous envoyons un message d'erreur indiquant qu'il s'agit d'un "invalid_code". enfin, le fichier URL doit être mis à jour pour inclure l'URL de cette vue

from rest_framework import serializers
from app_account.models import *

app_account/urls.py

Maintenant, nous pouvons ouvrir l'URL http://localhost:8555/api/account/activate/, nous utilisons une vue API personnalisée, elle n'obtient donc pas le champ requis

Django accounts management app ( registration and activation

Nous pouvons obtenir le code de la base de données (à des fins de test). La demande devrait ressembler à

from django.urls import path, include
from .views import *

urlpatterns = [

]

Si tout s'est bien passé, la réponse devrait ressembler à

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/account/', include('app_account.urls')),

]

C'est ça
Finissons-en ! Je sais que nous ne sommes pas encore connectés, mais c'est effectivement devenu un très long article, continuons dans le prochain article

Rester à l'écoute ?

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn