[PYTHON] Essayez de créer un site de gestion Todo en utilisant WebSocket avec Django (Swamp Dragon)

introduction

Lorsque j'ai recherché un package pour implémenter la communication WebSocket à l'aide de Django et AngularJS, Il y avait un Swamp Dragon qui avait tous les outils pour la communication WebSocket avec Django. J'ai créé un site de gestion Todo standard.

swampdragon: http://swampdragon.net/ github: https://github.com/jonashagstedt/swampdragon

Caractéristiques de Swamp Dragon

Il existe un serveur WebSocket dédié

Puisque WSGI de Django est HTTP, la communication WebSocket n'est pas possible, il est donc nécessaire de configurer un autre serveur. Lors de la création d'un projet via SwampDragon, un fichier appelé server.py est généré Cela démarrera le serveur. (Vous pouvez également le faire avec /manage.py runsd.py) Le serveur exécute le framework Web Tornado Dans server.py, l'URL requise pour la connexion est générée et démarrée.

La communication entre le client et le serveur lui-même utilise SockJS.

La classe Router est mappée à l'URL de server.py Envoi au client en utilisant la connexion SockJS détenue par la classe Router.

Il existe une fonction de mappage du modèle

Il sérialise et cartographie le modèle et les redis de Django. Lors de l'enregistrement d'un modèle, la fonction Pub / Sub de redis avertit le client en temps réel.

※「pub/sub」 Abréviation de «publier» et «s'abonner», qui signifie «publier» et «s'abonner» en japonais. Lorsqu'un utilisateur "publie" un événement sur une chaîne particulière Tous ceux qui «s'abonnent» à la chaîne seront informés de l'événement.

Les services utilisés par les clients sont également disponibles

Un service (js) qui permet au client de se connecter au serveur et de manipuler les données Cela ne prend pas beaucoup de temps car tout est préparé. (Objective-c tiers mais certains pour iOS)

Opérations pouvant être effectuées à partir du client

Peut également organiser des sessions utilisateur connectées

Étant donné que les informations utilisateur après la connexion peuvent être conservées côté serveur Il est possible d'inclure l'ID utilisateur, etc. dans des requêtes telles que lorsque des données sont acquises ou mises à jour. Il n'est pas nécessaire de disposer d'informations sur l'utilisateur côté client. L'auteur de Swamp Dragon propose de tenir la session Vous devez installer le package SwampDragon-auth.

Créer un site de gestion Todo à l'aide de Swamp Dragon de Django

Environnement d'exécution

Structure du répertoire

La structure des répertoires est la suivante L'application utilise AngularJS et il existe plusieurs fichiers JS, mais je les omis

application
├── app
│   ├── index.html
│   ├── login.html
├── manage.py
├── module
│   ├── middleware.py
│   └── todo
│       ├── models.py
│       ├── routers.py
│       └── serializers.py
├── server.py
├── settings.py
├── urls.py
└── wsgi.py

settings.py Paramètres du middleware et du swampdragon

INSTALLED_APPS = (
    :
    'swampdragon',
    'module.todo',
)

MIDDLEWARE_CLASSES = (
    :
    'module.middleware.AuthenticationMiddleware',
)

# SwampDragon settings
SWAMP_DRAGON_CONNECTION = ('swampdragon_auth.socketconnection.HttpDataConnection', '/data')
DRAGON_URL = 'http://localhost:9999/'

urls.py Étant donné que le traitement équivalent à Views est effectué par AngularJS sur le client, préparez une URL uniquement pour index.html.

# -*- coding: utf-8 -*-

from django.conf.urls import include, url
from django.contrib import admin
from django.views.generic import TemplateView

urlpatterns = [
    url(r'^$', TemplateView.as_view(template_name='index.html'), name='index'),
    url(r'^login', 'django.contrib.auth.views.login', kwargs={'template_name': 'login.html'}, name='login'),
    url(r'^logout', 'django.contrib.auth.views.logout_then_login', kwargs={'login_url': 'login'}, name='logout'),
    url(r'^admin/', include(admin.site.urls)),
]

middleware.py L'accès qui n'est pas connecté doit être ignoré vers la page de connexion

# -*- coding: utf-8 -*-

from django.shortcuts import redirect


class AuthenticationMiddleware(object):

    def process_request(self, request):
        if request.user.is_authenticated():
            if request.path.startswith('/login'):
                return redirect('/')
        elif request.path == '/':
            return redirect('login')

serializers.py Une classe qui définit l'échange de données avec le front-end --model: Définit le modèle avec "nom de module.model nom de classe" --publish_fields: Définition des colonnes pour notifier les clients --update_fields: définissez les colonnes qui peuvent être mises à jour depuis le client

from swampdragon.serializers.model_serializer import ModelSerializer


class UserSerializer(ModelSerializer):

    class Meta:
        model = 'auth.User'
        publish_fields = ('username',)


class TodoListSerializer(ModelSerializer):

    class Meta:
        model = 'todo.TodoList'
        publish_fields = ('name', 'description')
        update_fields = ('name', 'description')


class TodoItemSerializer(ModelSerializer):

    class Meta:
        model = 'todo.TodoItem'
        publish_fields = ('todolist_id', 'done', 'name', 'updated_at')
        update_fields = ('todolist_id', 'done', 'name')

models.py Héritez de SelfPublishModel pour que Publish soit notifié lors de l'enregistrement. Définissez une classe qui a été sérialisée avec serializer_class.

# -*- coding: utf-8 -*-

from django.db import models
from swampdragon.models import SelfPublishModel
from .serializers import TodoListSerializer, TodoItemSerializer


class TodoList(SelfPublishModel, models.Model):
    serializer_class = TodoListSerializer
    user_id = models.IntegerField()
    name = models.CharField(max_length=100)
    description = models.TextField(u'La description', blank=True, null=True)
    created_at = models.DateTimeField(u'Date et heure de création', auto_now_add=True)
    updated_at = models.DateTimeField(u'Mettre à jour la date et l'heure', auto_now=True)

    class Meta:
        index_together = ['user_id', 'id']


class TodoItem(SelfPublishModel, models.Model):
    serializer_class = TodoItemSerializer
    user_id = models.IntegerField()
    name = models.CharField(max_length=100)
    todolist_id = models.IntegerField()
    done = models.BooleanField(u'Drapeau d'achèvement', default=False)
    created_at = models.DateTimeField(u'Date et heure de création', auto_now_add=True)
    updated_at = models.DateTimeField(u'Mettre à jour la date et l'heure', auto_now=True)

    class Meta:
        index_together = ['user_id', 'id']

routers.py URL à enregistrer sur le serveur dédié WebSocket, classe qui définit le processus mappé --route_name: chemin de l'URL enregistrée dans le serveur dédié WebSocket (http: // localhost: 9999 / todo-list feeling) --get_initial: définit des paramètres supplémentaires à inclure lors de l'ajout, de la mise à jour ou de la suppression de données du client --get_subscription_contexts: Définit les paramètres à inclure dans le canal lorsque le client s'abonne --get_object: Traitement des requêtes lorsque les données sont demandées par elles-mêmes (obligatoire) --get_query_set: Traitement des requêtes lorsque des données sont demandées dans une liste (obligatoire)

# -*- coding: utf-8 -*-

from swampdragon import route_handler
from swampdragon.route_handler import ModelRouter
from module.todo.models import TodoList, TodoItem
from module.todo.serializers import UserSerializer, TodoListSerializer, TodoItemSerializer


class UserRouter(ModelRouter):
    route_name = 'user'
    serializer_class = UserSerializer

    def get_object(self, **kwargs):
        return self.connection.user

    def get_query_set(self, **kwargs):
        pass


class TodoListRouter(ModelRouter):
    route_name = 'todo-list'
    serializer_class = TodoListSerializer
    model = TodoList

    def get_initial(self, verb, **kwargs):
        kwargs['user_id'] = self.connection.user.id
        return kwargs

    def get_subscription_contexts(self, **kwargs):
        #Créez un canal unique avec votre ID utilisateur afin que les notifications de mise à jour ne soient envoyées qu'aux utilisateurs connectés(todolist|user_id:Devenez un canal)
        kwargs['user_id'] = self.connection.user.id
        return kwargs

    def get_object(self, **kwargs):
        user_list = self.model.objects.filter(id=kwargs['id'], user_id=self.connection.user.id)
        return user_list[0] if user_list else None

    def get_query_set(self, **kwargs):
        user_id = self.connection.user.id
        return self.model.objects.filter(user_id=user_id)


class TodoItemRouter(ModelRouter):
    route_name = 'todo-item'
    serializer_class = TodoItemSerializer
    model = TodoItem

    def get_initial(self, verb, **kwargs):
        kwargs['user_id'] = self.connection.user.id
        return kwargs

    def get_subscription_contexts(self, **kwargs):
        kwargs['user_id'] = self.connection.user.id
        return kwargs

    def get_object(self, **kwargs):
        user_list = self.model.objects.filter(id=kwargs['id'], user_id=self.connection.user.id)
        return user_list[0] if user_list else None

    def get_query_set(self, **kwargs):
        user_id = self.connection.user.id
        return self.model.objects.filter(user_id=user_id)


route_handler.register(UserRouter)
route_handler.register(TodoListRouter)
route_handler.register(TodoItemRouter)

client

Le client utilise le côté Angular JS $ dragon est un service fourni par Swamp Dragon.

angular.module('todoApp')
  .controller('PageController', ['$scope', '$dragon', '$dataHandler',
                                 function ($scope, $dragon, $dataHandler) {
    $scope.todoListChannel = 'todoListClient';
    $scope.todoItemChannel = 'todoItemClient';

    //Lors de l'accès à la première page
    $dragon.onReady(function() {
        // todolist,Abonnez-vous aux informations de todoItem(Une notification de modification sera envoyée)
        $dragon.subscribe('todo-list', $scope.todoListChannel, {}).then(function(response) {
            $scope.TodoListMapper = new DataMapper(response.data);
        });

        $dragon.subscribe('todo-item', $scope.todoItemChannel, {}).then(function(response) {
            $scope.todoItemMapper = new DataMapper(response.data);
        });

        // todolist, todoItem,Obtenir les données utilisateur
        $dragon.getSingle('user', {}).then(function(response) {
            $dataHandler.user = response.data;
        });

        $dragon.getList('todo-list', {list_id: 1}).then(function(response) {
            $dataHandler.todoLists = response.data;
        });

        $dragon.getList('todo-item', {list_id: 1}).then(function(response) {
            $dataHandler.todoItems = response.data;
        });
    });

    // todolist,Modifier la notification en cas de sauvegarde dans todoItem
    $dragon.onChannelMessage(function(channels, message) {

        if (indexOf.call(channels, $scope.todoListChannel) > -1) {
            $scope.$apply(function() {
                $scope.TodoListMapper.mapData($dataHandler.todoLists, message);
            });
        }

        if (indexOf.call(channels, $scope.todoItemChannel) > -1) {
            $scope.$apply(function() {
                $scope.todoItemMapper.mapData($dataHandler.todoItems, message);
            });
        }
    });

}]);

Commencez

python ./manage.py runserver
python server.py

Résumé

Le côté serveur est très facile à faire et je pense que c'est familier à quiconque a touché Django. Cependant, du côté client, un traitement tel que le rappel JS qui met à jour l'écran au format HTML en temps réel est effectué. Ambiance qui semble devoir travailler dur. Si vous utilisez AngularJS, vous pouvez lier des données entre des variables HTML et JS, il semble donc que vous puissiez améliorer le problème de la mise à jour de l'écran.

Il semble qu'il n'y ait pas beaucoup de disque d'introduction au Japon, mais si vous regardez github Il semble qu'il soit utilisé ici et là, alors j'aimerais m'y attendre à l'avenir.

Le code du site de gestion Todo créé cette fois est placé sur github. https://github.com/fujimisakari/todo-server

Recommended Posts

Essayez de créer un site de gestion Todo en utilisant WebSocket avec Django (Swamp Dragon)
Les utilisateurs de Rails essaient de créer un moteur de blog simple avec Django
Créez une application de gestion de score shogi à l'aide de Django 3 ~ Paramètres du site de gestion par défaut de Django ~
Créer une application Todo avec Django REST Framework + Angular
Essayez de créer un Checkbutton dynamiquement avec Tkinter en Python
(Python) Essayez de développer une application Web en utilisant Django
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 1 ~
Essayez de créer une application Todo avec le framework Django REST
Créer une application Todo avec Django ③ Créer une page de liste de tâches
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 2 ~
Créer une application Todo avec Django ⑤ Créer une fonction d'édition de tâches
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 3 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 4 ~
[CRUD] [Django] Créer un site CRUD en utilisant le framework Python Django ~ 5 ~
Créer une page d'accueil avec django
Créer une application de gestion de partition shogi à l'aide de Django 5 ~ Passer les données de la base de données au modèle ~
Créez une application de gestion de partition shogi à l'aide de Django 4 ~ Créer une vue ~
Créer une application Todo avec Django ① Créer un environnement avec Docker
Django Tips-Créez un site de classement avec Django-
Créer un téléchargeur de fichiers avec Django
Créez une application de gestion de score shogi à l'aide de Django 2 ~ Paramètres de la base de données ~
Créez une application de gestion de partition shogi à l'aide de Django 6 ~ Split Template ~
Essayez de créer un environnement python avec Visual Studio Code et WSL
J'ai essayé de créer une application todo en utilisant une bouteille avec python
Essayez de créer un article de Qiita avec l'API REST [Préparation environnementale]
Créer une API REST pour faire fonctionner dynamodb avec le Framework Django REST
[Django 2.2] Ajouter un nouveau badge aux nouveaux messages avec une date à l'aide d'un filtre de modèle
Créez un outil qui secoue automatiquement furigana avec html en utilisant Mecab de Python3
Si vous souhaitez créer une application TODO (distribuée) en utilisant uniquement Python-Extension 1
Créer une application Todo avec Django ④ Implémenter la fonction de création de dossier et de tâche
[Python] [Word] [python-docx] Essayez de créer un modèle de phrase de mot en Python en utilisant python-docx
Essayez d'utiliser django-import-export pour ajouter des données csv à django
Comment développer une application de panier avec Django
Essayez de dessiner une courbe de vie avec python
Essayez de créer un code de "décryptage" en Python
Créez un tableau de bord pour les appareils réseau avec Django!
Étapes pour créer un bot Twitter avec Python
Essayez de créer une nouvelle commande sous Linux
Essayez de créer un groupe de dièdre avec Python
Procédure de création d'application multi-plateforme avec kivy
Essayez de créer un serveur HTTP en utilisant Node.js
Créez une application Hello World avec un seul fichier avec django
[Chat De Tornado] Créez un chat en utilisant WebSocket dans Tornado
Liste de tâches simple créée avec Python + Django
Comment créer une API Rest dans Django
Essayez de créer une table d'enregistrement de bataille avec matplotlib à partir des données de "Schedule-kun"
Comment créer rapidement un environnement d'apprentissage automatique à l'aide de Jupyter Notebook avec UbuntuServer 16.04 LTS
Essayez de créer une forme d'onde (spectre audio) qui se déplace en fonction du son avec python
Faisons un outil de veille de commande avec python
Comment créer un sous-menu avec le plug-in [Blender]
[Python] Générer ValueObject avec un constructeur complet à l'aide de classes de données
Essayez de créer une API RESTful avec MVC à l'aide de Flask 1.0.2
Un échantillon pour essayer rapidement les machines de factorisation avec fastFM
Je souhaite créer manuellement une légende avec matplotlib
Transition vers l'écran de mise à jour avec le Django a tag
À moi-même en tant que débutant Django (1) -Création d'un projet / application-
[Python] Comment créer un histogramme bidimensionnel avec Matplotlib
À moi-même en tant que débutant Django (4) --Créer une application mémo-