[PYTHON] Versuchen Sie, mit WebSocket mit Django (Swamp Dragon) eine Todo-Verwaltungssite zu erstellen.

Einführung

Als ich nach einem Paket zur Implementierung der WebSocket-Kommunikation mit Django und AngularJS suchte, Es gab einen Sumpfdrachen, der alle Tools für die WebSocket-Kommunikation mit Django hatte. Ich habe eine Standard-Todo-Verwaltungssite erstellt.

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

Eigenschaften von Swamp Dragon

Es gibt einen dedizierten WebSocket-Server

Da es sich bei WSGI von Django um HTTP handelt, ist keine WebSocket-Kommunikation möglich. Daher muss ein anderer Server eingerichtet werden. Beim Erstellen eines Projekts über SwampDragon wird eine Datei mit dem Namen server.py generiert Dadurch wird der Server gestartet. (Sie können dies auch mit /manage.py runningd.py tun.) Auf dem Server wird das Webframework Tornado ausgeführt In server.py wird die für die Verbindung erforderliche URL generiert und gestartet.

Die Kommunikation zwischen dem Client und dem Server selbst verwendet SockJS.

Die Router-Klasse wird der URL von server.py zugeordnet Senden an den Client über die SockJS-Verbindung der Router-Klasse.

Es gibt eine Mapper-Funktion des Modells

Es serialisiert und kartiert Djangos Modell und Redis. Beim Speichern eines Modells benachrichtigt die Pub / Sub-Funktion von redis den Client in Echtzeit.

※「pub/sub」 Abkürzung für "veröffentlichen" und "abonnieren", was auf Japanisch "veröffentlichen" und "abonnieren" bedeutet. Wenn jemand ein Ereignis auf einem bestimmten Kanal "veröffentlicht" Jeder, der den Kanal "abonniert", wird über die Veranstaltung informiert.

Von Kunden genutzte Dienste sind ebenfalls verfügbar

Ein Dienst (js), mit dem der Client eine Verbindung zum Server herstellen und die Daten bearbeiten kann Es dauert nicht lange, weil alles vorbereitet ist. (Objective-c von Drittanbietern, einige jedoch für iOS)

Vorgänge, die vom Client aus ausgeführt werden können

--Eine Liste von Daten abrufen

Kann auch verbundene Benutzersitzungen abhalten

Da Benutzerinformationen nach dem Anmelden auf der Serverseite beibehalten werden können Es ist möglich, Benutzer-IDs usw. in Abfragen aufzunehmen, z. B. wenn Daten erfasst oder aktualisiert werden. Auf der Clientseite müssen keine Benutzerinformationen vorhanden sein. Der Autor von Swamp Dragon bietet an, die Sitzung abzuhalten Das SwampDragon-auth-Paket muss installiert sein.

Erstellen Sie eine Todo-Verwaltungssite mit Djangos Sumpfdrachen

Ausführungsumgebung

Verzeichnisaufbau

Die Verzeichnisstruktur ist wie folgt Die App verwendet AngularJS und es gibt mehrere JS-Dateien, aber ich lasse sie weg

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 Einstellungen für Middleware und 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 Da die Verarbeitung, die Ansichten entspricht, von AngularJS auf dem Client ausgeführt wird, bereiten Sie eine URL nur für index.html vor.

# -*- 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 Zugriff, der nicht angemeldet ist, sollte zur Anmeldeseite übersprungen werden

# -*- 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 Eine Klasse, die den Datenaustausch mit dem Frontend definiert --model: Definieren Sie das Modell mit "module name.model class name" --publish_fields: Definition von Spalten zur Benachrichtigung von Clients --update_fields: Definieren Sie Spalten, die vom Client aus aktualisiert werden können

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 Erben Sie SelfPublishModel, damit Publish beim Speichern benachrichtigt wird. Definieren Sie eine Klasse, die mit serializer_class serialisiert wurde.

# -*- 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'Erläuterung', blank=True, null=True)
    created_at = models.DateTimeField(u'Erstellungsdatum und -zeit', auto_now_add=True)
    updated_at = models.DateTimeField(u'Datum und Uhrzeit aktualisieren', 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'Abschlussflag', default=False)
    created_at = models.DateTimeField(u'Erstellungsdatum und -zeit', auto_now_add=True)
    updated_at = models.DateTimeField(u'Datum und Uhrzeit aktualisieren', auto_now=True)

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

routers.py URL, die auf dem dedizierten WebSocket-Server registriert werden soll, Klasse, die den zugeordneten Prozess definiert --route_name: Pfad der URL, die auf dem dedizierten WebSocket-Server registriert ist (http: // localhost: 9999 / todo-list-Gefühl) --get_initial: Definieren Sie zusätzliche Parameter, die beim Hinzufügen, Aktualisieren oder Löschen von Daten vom Client berücksichtigt werden sollen --get_subscription_contexts: Definieren Sie die Parameter, die beim Abonnieren des Clients in den Kanal aufgenommen werden sollen --get_object: Abfrageverarbeitung, wenn Daten von selbst angefordert werden (erforderlich) --get_query_set: Abfrageverarbeitung, wenn Daten in einer Liste angefordert werden (erforderlich)

# -*- 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):
        #Erstellen Sie einen eindeutigen Kanal mit Ihrer Benutzer-ID, damit Aktualisierungsbenachrichtigungen nur an angemeldete Benutzer gesendet werden(todolist|user_id:Werde ein Kanal)
        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)

Klient

Der Client verwendet die Angular JS-Seite $ dragon ist ein Service von Swamp Dragon.

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

    //Beim Zugriff auf die erste Seite
    $dragon.onReady(function() {
        // todolist,Abonnieren Sie todoItem-Informationen(Änderungsbenachrichtigung wird gesendet)
        $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,Benutzerdaten abrufen
        $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,Ändern Sie die Benachrichtigung, wenn in todoItem gespeichert wird
    $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);
            });
        }
    });

}]);

Anlaufen

python ./manage.py runserver
python server.py

Zusammenfassung

Die Serverseite ist sehr einfach zu machen und ich denke, sie ist jedem bekannt, der Django berührt hat. Auf der Clientseite erfolgt jedoch eine Verarbeitung wie ein JS-Rückruf, bei dem der Bildschirm in Echtzeit auf HTML aktualisiert wird. Atmosphäre, die hart arbeiten muss. Wenn Sie AngularJS verwenden, können Sie Daten zwischen HTML- und JS-Variablen binden, sodass Sie anscheinend die Probleme beim Aktualisieren des Bildschirms verbessern können.

Es scheint, dass es in Japan nicht viel Einführungsrekord gibt, aber wenn man sich Github ansieht Es scheint, dass es hier und da verwendet wird, also würde ich es gerne in Zukunft erwarten.

Der Code der diesmal erstellten Todo-Verwaltungssite wird auf github abgelegt. https://github.com/fujimisakari/todo-server

Recommended Posts

Versuchen Sie, mit WebSocket mit Django (Swamp Dragon) eine Todo-Verwaltungssite zu erstellen.
Rails-Benutzer versuchen, mit Django eine einfache Blog-Engine zu erstellen
Erstellen Sie eine Shogi-Score-Management-App mit Django 3 ~ Django Standard-Management-Site-Einstellungen ~
Erstellen Sie eine Todo-App mit Django REST Framework + Angular
Versuchen Sie, mit Tkinter in Python dynamisch einen Checkbutton zu erstellen
(Python) Versuchen Sie, eine Webanwendung mit Django zu entwickeln
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 1 ~
Lassen Sie uns eine Todo-App mit dem Django REST-Framework erstellen
Todo-App mit Django erstellen ③ Aufgabenlistenseite erstellen
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 2 ~
Todo-App mit Django erstellen ⑤ Funktion zum Bearbeiten von Aufgaben erstellen
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 3 ~
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 4 ~
[CRUD] [Django] Erstellen Sie eine CRUD-Site mit dem Python-Framework Django ~ 5 ~
Erstellen Sie eine Homepage mit Django
Erstellen Sie eine Shogi-Score-Management-Anwendung mit Django 5 ~ DB-Daten an Vorlage übergeben ~
Erstellen Sie eine Shogi Score Management App mit Django 4 ~ Create View ~
Erstellen einer Todo-App mit Django ① Erstellen Sie eine Umgebung mit Docker
Django-Tipps - Erstellen Sie eine Ranking-Site mit Django-
Erstellen Sie mit Django einen Datei-Uploader
Erstellen Sie eine Shogi Score Management App mit Django 2 ~ Datenbankeinstellungen ~
Erstellen Sie eine Shogi Score Management App mit Django 6 ~ Split Template ~
Versuchen Sie, eine Python-Umgebung mit Visual Studio Code & WSL zu erstellen
Ich habe versucht, eine ToDo-App mit einer Flasche mit Python zu erstellen
Versuchen Sie, einen Artikel von Qiita mit der REST-API [Umweltvorbereitung] zu erstellen.
Erstellen Sie eine REST-API, um dynamodb mit dem Django REST Framework zu betreiben
[Django 2.2] Fügen Sie neuen Posts mit einem Datum mithilfe eines Vorlagenfilters ein neues Abzeichen hinzu
Erstellen Sie mit Mecab aus Python3 ein Tool, das Furigana automatisch mit HTML schüttelt
Wenn Sie eine TODO-Anwendung (verteilt) nur mit Python-Extension 1 erstellen möchten
Todo-App mit Django erstellen ④ Ordner- und Aufgabenerstellungsfunktion implementieren
[Python] [Word] [python-docx] Versuchen Sie, mit python-docx eine Vorlage für einen Wortsatz in Python zu erstellen
Versuchen Sie, mit django-import-export csv-Daten zu django hinzuzufügen
So entwickeln Sie eine Cart-App mit Django
Versuchen Sie, mit Python eine Lebenskurve zu zeichnen
Versuchen Sie, in Python einen "Entschlüsselungs" -Code zu erstellen
Erstellen Sie mit Django ein Dashboard für Netzwerkgeräte!
Schritte zum Erstellen eines Twitter-Bots mit Python
Versuchen Sie, einen neuen Befehl unter Linux zu erstellen
Versuchen Sie, mit Python eine Diedergruppe zu bilden
Verfahren zur Erstellung plattformübergreifender Apps mit kivy
Versuchen Sie, mit Node.js einen HTTP-Server zu erstellen
Erstellen Sie mit Django eine Hallo-Welt-Anwendung mit nur einer Datei
[Chat De Tornado] Erstellen Sie einen Chat mit WebSocket in Tornado
Einfache Aufgabenliste, erstellt mit Python + Django
So erstellen Sie eine Rest-API in Django
Versuchen Sie, mit matplotlib aus den Daten von "Schedule-kun" eine Kampfaufzeichnungstabelle zu erstellen.
So erstellen Sie schnell eine maschinelle Lernumgebung mit Jupyter Notebook mit UbuntuServer 16.04 LTS
Versuchen Sie, mit Python eine Wellenform (Audiospektrum) zu erstellen, die sich entsprechend dem Klang bewegt
Lassen Sie uns ein Befehls-Standby-Tool mit Python erstellen
So erstellen Sie ein Untermenü mit dem Plug-In [Blender]
[Python] Generieren Sie ValueObject mit dem vollständigen Konstruktor mithilfe von Datenklassen
Versuchen Sie, mit MVC eine RESTful-API mit Flask 1.0.2 zu erstellen
Ein Beispiel, um Faktorisierungsmaschinen schnell mit fastFM auszuprobieren
Ich möchte manuell eine Legende mit matplotlib erstellen
Übergang zum Update-Bildschirm mit dem Django-Tag
Für mich als Django-Anfänger (1) -Erstellen eines Projekts / einer App-
[Python] So erstellen Sie mit Matplotlib ein zweidimensionales Histogramm
Für mich als Django-Anfänger (4) - Erstellen Sie eine Memo-App-