La maisonapplicationComment nous avons créé une application Full-Stack. Un réseau social utilisant Django et React | de Michael Sheinman | janvier 2023
Comment nous avons créé une application Full-Stack. Un réseau social utilisant Django et React | de Michael Sheinman | janvier 2023
J’ai récemment développé Restify, une application de médias sociaux pour les restaurants. Restify est une application full-stack utilisant Django et React. Le but de ce projet était de pratiquer le développement full-stack. Dans cet article, je vais décrire le fonctionnement de l’application.
Modèle de données
Restify est un réseau social pour les restaurants. Un utilisateur peut créer une page de restaurant qui comprend des informations de base correspondantes, des éléments de menu, des images et des articles de blog.
Page d’un restaurateur factice
Les utilisateurs peuvent suivre, aimer et commenter les restaurants. Cela conduit à de nombreuses relations entre les entités et convient parfaitement à une base de données relationnelle. Nous avons gardé la conception simple et nous avons utilisé Sqlite3 avec Django Object-Relational Mapping (ORM) pour la base de données. Le diagramme Entité-Relation suivant montre le modèle de données.
Diagramme ERD Restify simplifié
La plupart des entités partagent des relations avec le Restaurant. Certaines de ces relations sont un-à-plusieurs : un restaurant propose de nombreux éléments de menu, articles de blog et images uniques. Pour ces relations, nous avons créé des clés étrangères vers l’objet Restaurant. Par exemple, voici la définition d’un objet image de restaurant :
En revanche, les relations utilisateur-restaurant sont toutes de type plusieurs à plusieurs. Ces relations nécessitent des tables supplémentaires. Voici la définition de la table Commentaire.
class Comment(models.Model): user = models.ForeignKey(to=ModifiedUser, related_name='comment', on_delete=models.CASCADE) timestamp = models.DateTimeField(auto_created=True, auto_now_add=True) restaurant = models.ForeignKey(to=Restaurant, related_name='restaurant_comment', on_delete=models.CASCADE) contents = models.CharField(max_length=250)
Cette table a des clés étrangères à la fois pour l’utilisateur et les objets du restaurant. La table possède également des attributs supplémentaires pour le contenu et l’horodatage.
Structure dorsale
Le backend expose une interface API REST. Nous avons utilisé le framework de repos Django avec ses vues génériques. La structure principale est :
URL : points d’entrée pour les appels d’API. Les urls diriger un chemin vers une vue correspondante. Restify a trois URL : admin, restaurants et compte.
Vues : points de terminaison de l’API. Ces classes héritent des classes d’API génériques des frameworks de repos de Django et remplacent les attributs basés sur la logique métier.
Modèles : entités du programme. Django convertit les classes en tables de base de données. Les attributs représentent les champs de la base de données.
Sérialiseurs : objets permettant de convertir des données complexes en types de données natifs pouvant être rendus au format JSON.
Gestion administrative
Django autorise nativement les super-utilisateurs. Les superutilisateurs contrôlent le système et peuvent modifier les données. Vous pouvez utiliser la commande suivante pour créer un superutilisateur :
Une fois la configuration terminée, nous avions une vue d’administration fonctionnelle. Voici une capture d’écran :
Vue d’administration de Django
Authentification
Nous avons implémenté l’authentification à l’aide de jetons Json Web Tokens (JWT). Une demande de connexion génère un nouveau jeton JWT. Ensuite, le jeton est envoyé dans toutes les requêtes ultérieures entre le client et le serveur. Dans settings.py, nous avons configuré la durée de vie d’un jeton à un jour.
Nous avons utilisé React pour le frontend. Nous avons démarré l’application avec Créer une application React. Nous avons également utilisé Interface utilisateur des chakras pour la conception. Chakra UI est une bibliothèque de composants React avec prise en charge intégrée de la réactivité, de la thématisation et de l’accessibilité. La structure frontale est :
App.js : configure les routes vers les vues d’application. La vue initiale est la page de destination.
Modules : Vues de l’application. Les vues changent en fonction du type d’utilisateur (par exemple, les propriétaires de restaurant), nous utilisons donc un crochet pour déterminer ce qu’il faut afficher.
Composants : Parties réutilisables des vues. Les composants remplissent les données en envoyant une requête API au backend à l’aide d’axios.
Hooks : fonctions personnalisées pour se connecter à l’état React.
Pagination
Restify implémente la pagination pour la plupart des entités. Sur le backend, nous avons configuré settings.py afin que le reste du framework prenne en charge la pagination en utilisant :
Ensuite, nous pouvons simplement définir la propriété pagination_class, comme suit :
class NotificationView(generics.ListAPIView): pagination_class = PageNumberPagination ...
Côté frontend, nous avons implémenté le tutoriel freecodecamp. Nous avons défini un crochet usePagination et un composant de pagination pour utiliser le crochet et afficher la plage correspondante. Voici un exemple de pagination :
Avis
Les restaurateurs reçoivent une notification lorsqu’un utilisateur aime, commente ou suit leur restaurant. Les utilisateurs reçoivent également des notifications lorsqu’un restaurant qu’ils suivent met à jour le menu ou publie un nouveau blog. Une entité de notification stocke le notifiant, le destinataire et d’autres informations pertinentes. Les notifications en temps réel étaient hors de portée, nous avons donc mis en place un tirer l’architecture en utilisant REST à la place.
Une architecture pull oblige les utilisateurs à extraire périodiquement les notifications. Nous avons mis en place des pulls chaque fois qu’un utilisateur se déplace vers une page différente. Voici l’interface backend REST pour les notifications :
OBTENIR : /comptes/notifications/?page=
PATCH : /accounts/notifications/viewed/
SUPPRIMER : /accounts/notifications/
Lorsque les utilisateurs lancent une page pour la première fois, la requête GET récupère la première notification. À ce stade, toutes les notifications ne sont pas lues. Une fois qu’un utilisateur clique sur une notification, nous envoyons une demande PATCH pour marquer la notification comme vue. L’interface marque temporairement la notification comme cochée.
Affichage de la page des notifications
Enfin, lorsque l’utilisateur quitte la page de notification ou se déplace vers une autre page, nous envoyons une opération DELETE à toutes les notifications cochées.
Problème CORS
L’un des défis était les problèmes de CORS lorsque nous avons essayé de connecter le frontend et le backend. SCRO signifie Cross-Origin Resource Sharing. Il s’agit d’un mécanisme basé sur un en-tête HTTP qui permet à un serveur d’indiquer des origines valides pour le chargement des ressources.
Alors que notre backend fonctionnait avec Postman, nous ne pouvions pas combiner les pièces. Lorsque le navigateur a envoyé des demandes, les demandes ont produit une erreur indiquant que l’accès a été bloqué par la politique CORS en raison d’un en-tête manquant.
Nous avons résolu le problème CORS en installant django-cors-headers. Nous avons également configuré les modifications suivantes dans settings.py :
Cela configure CORS pour autoriser toutes les origines, ce qui était suffisant pour le développement local.
Configuration de la documentation
Nous avons également rencontré un défi avec la mise en place de la documentation de Django. Nous avons configuré Swagger en ajoutant la dépendance django-rest-swagger et en configurant les paramètres Swagger correspondants.
La documentation manquait de détails sur les codes de réponse et leur description. Le point de terminaison d’inscription renvoie également 409 si un nom d’utilisateur existe déjà. Le même problème s’applique à tous les terminaux. La génération de schéma de cadre de repos de Django ne prend pas en charge les réponses.
Un utilisateur de StackOverflow avait le même problème. Il n’existe actuellement aucune solution efficace connue. Nous avons fini par prendre le code HTML généré par Swagger et ajouter manuellement tous les codes de réponse.
Comment nous avons créé une application Full-Stack. Un réseau social utilisant Django et React | de Michael Sheinman | janvier 2023
Un réseau social utilisant Django et React
J’ai récemment développé Restify, une application de médias sociaux pour les restaurants. Restify est une application full-stack utilisant Django et React. Le but de ce projet était de pratiquer le développement full-stack. Dans cet article, je vais décrire le fonctionnement de l’application.
Modèle de données
Restify est un réseau social pour les restaurants. Un utilisateur peut créer une page de restaurant qui comprend des informations de base correspondantes, des éléments de menu, des images et des articles de blog.
Les utilisateurs peuvent suivre, aimer et commenter les restaurants. Cela conduit à de nombreuses relations entre les entités et convient parfaitement à une base de données relationnelle. Nous avons gardé la conception simple et nous avons utilisé Sqlite3 avec Django Object-Relational Mapping (ORM) pour la base de données. Le diagramme Entité-Relation suivant montre le modèle de données.
La plupart des entités partagent des relations avec le Restaurant. Certaines de ces relations sont un-à-plusieurs : un restaurant propose de nombreux éléments de menu, articles de blog et images uniques. Pour ces relations, nous avons créé des clés étrangères vers l’objet Restaurant. Par exemple, voici la définition d’un objet image de restaurant :
class ImageModel(models.Model):
ref_img = models.ImageField(upload_to='restaurant_pics/', null=True, blank=True)
restaurant = models.ForeignKey(to=Restaurant, related_name='restaurant_images', on_delete=models.CASCADE)
En revanche, les relations utilisateur-restaurant sont toutes de type plusieurs à plusieurs. Ces relations nécessitent des tables supplémentaires. Voici la définition de la table Commentaire.
class Comment(models.Model):
user = models.ForeignKey(to=ModifiedUser, related_name='comment', on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_created=True, auto_now_add=True)
restaurant = models.ForeignKey(to=Restaurant, related_name='restaurant_comment', on_delete=models.CASCADE)
contents = models.CharField(max_length=250)
Cette table a des clés étrangères à la fois pour l’utilisateur et les objets du restaurant. La table possède également des attributs supplémentaires pour le contenu et l’horodatage.
Structure dorsale
Le backend expose une interface API REST. Nous avons utilisé le framework de repos Django avec ses vues génériques. La structure principale est :
urls
diriger un chemin vers une vue correspondante. Restify a trois URL : admin, restaurants et compte.Gestion administrative
Django autorise nativement les super-utilisateurs. Les superutilisateurs contrôlent le système et peuvent modifier les données. Vous pouvez utiliser la commande suivante pour créer un superutilisateur :
> python3 manage.py createsuperuser
Username: <your username goes here>
Email address: <your email goes here>
Password: <your password goes here>
Password (again): <your password goes here>
Superuser created successfully.
Nous avons configuré une route pour la console d’administration. Dans le
urls
fichier, nous avons ajouté le code suivant :from django.contrib import admin
urlpatterns = [
path('admin/', admin.site.urls),
...
]
De plus, nous avons enregistré tous les modèles dans un fichier admin.py.
from django.contrib import admin
from restaurants.models import Blog, Comment, ImageModel, ModifiedUser, Restaurant,
MenuItem, Notification
admin.site.register(Restaurant)
admin.site.register(ModifiedUser)
admin.site.register(MenuItem)
admin.site.register(Notification)
admin.site.register(Comment)
admin.site.register(Blog)
admin.site.register(ImageModel)
Enfin, nous avons modifié
settings.py
:INSTALLED_APPS = [
'django.contrib.admin',
...
]
Une fois la configuration terminée, nous avions une vue d’administration fonctionnelle. Voici une capture d’écran :
Authentification
Nous avons implémenté l’authentification à l’aide de jetons Json Web Tokens (JWT). Une demande de connexion génère un nouveau jeton JWT. Ensuite, le jeton est envoyé dans toutes les requêtes ultérieures entre le client et le serveur. Dans settings.py, nous avons configuré la durée de vie d’un jeton à un jour.
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(days=1),
}
Structure frontale
Nous avons utilisé React pour le frontend. Nous avons démarré l’application avec Créer une application React. Nous avons également utilisé Interface utilisateur des chakras pour la conception. Chakra UI est une bibliothèque de composants React avec prise en charge intégrée de la réactivité, de la thématisation et de l’accessibilité. La structure frontale est :
Pagination
Restify implémente la pagination pour la plupart des entités. Sur le backend, nous avons configuré settings.py afin que le reste du framework prenne en charge la pagination en utilisant :
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
...
}
Ensuite, nous pouvons simplement définir la propriété pagination_class, comme suit :
class NotificationView(generics.ListAPIView):
pagination_class = PageNumberPagination
...
Côté frontend, nous avons implémenté le tutoriel freecodecamp. Nous avons défini un crochet usePagination et un composant de pagination pour utiliser le crochet et afficher la plage correspondante. Voici un exemple de pagination :
Avis
Les restaurateurs reçoivent une notification lorsqu’un utilisateur aime, commente ou suit leur restaurant. Les utilisateurs reçoivent également des notifications lorsqu’un restaurant qu’ils suivent met à jour le menu ou publie un nouveau blog. Une entité de notification stocke le notifiant, le destinataire et d’autres informations pertinentes. Les notifications en temps réel étaient hors de portée, nous avons donc mis en place un tirer l’architecture en utilisant REST à la place.
Une architecture pull oblige les utilisateurs à extraire périodiquement les notifications. Nous avons mis en place des pulls chaque fois qu’un utilisateur se déplace vers une page différente. Voici l’interface backend REST pour les notifications :
Lorsque les utilisateurs lancent une page pour la première fois, la requête GET récupère la première notification. À ce stade, toutes les notifications ne sont pas lues. Une fois qu’un utilisateur clique sur une notification, nous envoyons une demande PATCH pour marquer la notification comme vue. L’interface marque temporairement la notification comme cochée.
Enfin, lorsque l’utilisateur quitte la page de notification ou se déplace vers une autre page, nous envoyons une opération DELETE à toutes les notifications cochées.
Problème CORS
L’un des défis était les problèmes de CORS lorsque nous avons essayé de connecter le frontend et le backend. SCRO signifie Cross-Origin Resource Sharing. Il s’agit d’un mécanisme basé sur un en-tête HTTP qui permet à un serveur d’indiquer des origines valides pour le chargement des ressources.
Alors que notre backend fonctionnait avec Postman, nous ne pouvions pas combiner les pièces. Lorsque le navigateur a envoyé des demandes, les demandes ont produit une erreur indiquant que l’accès a été bloqué par la politique CORS en raison d’un en-tête manquant.
Nous avons résolu le problème CORS en installant
django-cors-headers
. Nous avons également configuré les modifications suivantes dans settings.py :INSTALLED_APPS = [
'corsheaders'
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
]
CORS_ALLOW_ALL_ORIGINS = True
Cela configure CORS pour autoriser toutes les origines, ce qui était suffisant pour le développement local.
Configuration de la documentation
Nous avons également rencontré un défi avec la mise en place de la documentation de Django. Nous avons configuré Swagger en ajoutant la dépendance django-rest-swagger et en configurant les paramètres Swagger correspondants.
INSTALLED_APPS = [
'rest_framework_swagger',
...
]
SWAGGER_SETTINGS = {
'USE_SESSION_AUTH': False,
"is_authenticated": True,
"is_superuser": True,
'unauthenticated_user': 'django.contrib.auth.models.AnonymousUser',
}
Ensuite, dans le fichier urls, nous avons ajouté un modèle pour accéder à swagger.
urlpatterns = [
path('accounts/', include('accounts.urls', namespace='accounts')),
...
]
Cela a créé une documentation sous http://localhost:8000/api/docs/. Voici à quoi ressemblait la documentation :
La documentation manquait de détails sur les codes de réponse et leur description. Le point de terminaison d’inscription renvoie également 409 si un nom d’utilisateur existe déjà. Le même problème s’applique à tous les terminaux. La génération de schéma de cadre de repos de Django ne prend pas en charge les réponses.
Un utilisateur de StackOverflow avait le même problème. Il n’existe actuellement aucune solution efficace connue. Nous avons fini par prendre le code HTML généré par Swagger et ajouter manuellement tous les codes de réponse.
Télécharger ici