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
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 Router-Klasse wird der URL von server.py zugeordnet Senden an den Client über die SockJS-Verbindung der Router-Klasse.
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.
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)
--Eine Liste von Daten abrufen
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.
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)
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);
});
}
});
}]);
python ./manage.py runserver
python server.py
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