Nous avons créé la structure du projet dans l'article précédent, cet article s'appuiera sur elle. ça couvrira
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
Consultez les articles précédents si vous êtes intéressé !
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/"
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 :
Nous avons également ajouté plusieurs champs pour cet utilisateur du projet qui sont
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.
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.
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)
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(...)
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.
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
on peut voir notre schéma dans le message d'erreur ?, cool, essayons d'enregistrer un nouvel utilisateur, je l'appellerai "test5@gmail.com"
ça a l'air bien, testons maintenant l'erreur de validation du sérialiseur, nous allons essayer d'enregistrer à nouveau le même utilisateur
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
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
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!