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
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 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 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.
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)
É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.
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)
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);
});
}
});
}]);
python ./manage.py runserver
python server.py
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