Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.
Étape 2 : examen du modèle de données et des détails de la mise en œuvre
2.1 : modèle de données de base
Cet exemple d'application met en évidence les concepts de modèle de données DynamoDB suivants :
-
Table – Dans DynamoDB, une table est un ensemble d'éléments (registres), et chaque élément est un ensemble de paires nom-valeur appelées attributs.
Dans cet Tic-Tac-Toe exemple, l'application stocke toutes les données du jeu dans un tableau,
Games
. L'application crée un élément par jeu dans la table et stocke toutes les données de jeux en tant qu'attributs. Une tic-tac-toe partie peut comporter jusqu'à neuf coups. Les tables DynamoDB n'ayant pas de schéma dans les cas où seule la clé primaire est l'attribut obligatoire, l'application peut stocker différents nombres d'attributs par élément de jeu.La table
Games
a une clé primaire simple composée d'un attribut,GameId
, de type chaîne. L'application attribue un ID unique à chaque partie. Pour plus d'informations sur les clés primaires DynamoDB, consultez Clé primaire.Lorsqu'un utilisateur lance un tic-tac-toe jeu en invitant un autre utilisateur à jouer, l'application crée un nouvel élément dans le
Games
tableau avec des attributs stockant les métadonnées du jeu, tels que les suivants :-
HostId
, l'utilisateur qui a lancé la partie. -
Opponent
, l'utilisateur qui a été invité à jouer. -
L'utilisateur dont c'est le tour de jouer. L'utilisateur qui a lancé la partie joue en premier.
-
L'utilisateur qui utilise le symbole O sur le plateau. L'utilisateur qui initie les parties utilise le symbole O.
En outre, l'application crée un attribut concaténé
StatusDate
, marquant l'état du jeu initial en tant quePENDING
. La capture d'écran suivante présente un exemple d'élément tel qu'il s'affiche dans la console DynamoDB :En cours de partie, l'application ajoute un attribut à la table pour chaque déplacement. Le nom d'attribut est la position sur le plateau, par exemple
TopLeft
ouBottomRight
. Par exemple, un déplacement peut avoir un attributTopLeft
avec la valeurO
, un attributTopRight
avec la valeurO
et un attributBottomRight
avec la valeurX
. La valeur d'attribut estO
ouX
, selon l'utilisateur qui a effectué le déplacement. Par exemple, considérez le plateau suivant. -
-
Attributs de valeur concaténée – L'attribut
StatusDate
illustre un attribut de valeur concaténée. Dans cette approche, au lieu de créer des attributs distincts pour stocker le statut du jeu (PENDING
,IN_PROGRESS
etFINISHED
) et la date (moment du dernier déplacement), vous les associez en un seul attribut, par exempleIN_PROGRESS_2014-04-30 10:20:32
.L'application utilise ensuite l'attribut
StatusDate
pour la création d'index secondaires en spécifiantStatusDate
comme clé de tri pour l'index. L'avantage d'utiliser l'attribut de valeur concaténéeStatusDate
est illustré plus en détails dans les index abordés par la suite. -
Index secondaires globaux – Vous pouvez utiliser la clé primaire de la table,
GameId
, pour interroger efficacement la table afin de trouver un élément de jeu. Pour interroger la table sur des attributs autres que les attributs de clé primaires, DynamoDB prend en charge la création d'index secondaires. Dans cet exemple d'application, vous créez les deux index secondaires suivants :-
HostId- StatusDate -indice. Cet index a
HostId
comme clé de partition etStatusDate
comme une clé de tri. Vous pouvez utiliser cet index pour interroger surHostId
, par exemple pour trouver des jeux hébergés par un utilisateur particulier. -
OpponentId- StatusDate -indice. Cet index a
OpponentId
comme clé de partition etStatusDate
comme une clé de tri. Vous pouvez utiliser cet index pour interroger surOpponent
, par exemple pour trouver des jeux dans lesquels un utilisateur particulier est l'adversaire.
Ces index sont appelés index secondaires globaux, car la clé de partition dans ces index n'est pas la même que la clé de partition (
GameId
) utilisée dans la clé primaire de la table.Notez que les deux index spécifient
StatusDate
comme clé de tri. Cela permet d'effectuer les opérations suivantes :-
Vous pouvez interroger à l'aide de l'opérateur de comparaison
BEGINS_WITH
. Par exemple, vous pouvez trouver tous les jeux avec l'attributIN_PROGRESS
hébergés par un utilisateur particulier. Dans ce cas, l'opérateurBEGINS_WITH
vérifie la valeurStatusDate
qui commence parIN_PROGRESS
. -
DynamoDB stocke les éléments dans l'index dans l'ordre, par valeur de clé de tri. Ainsi, si tous les préfixes de statut sont identiques (par exemple,
IN_PROGRESS
), le ISO format utilisé pour la partie date comportera des éléments triés du plus ancien au plus récent. Cette approche permet d'effectuer certaines requêtes efficacement, par exemple les éléments suivants :-
Récupérez jusqu'à 10 des jeux
IN_PROGRESS
les plus récents organisés par l'utilisateur qui est connecté. Pour cette requête, vous spécifiez l'indexHostId-StatusDate-index
. -
Récupérez jusqu'à 10 des jeux
IN_PROGRESS
les plus récents où l'utilisateur connecté est l'adversaire. Pour cette requête, vous spécifiez l'indexOpponentId-StatusDate-index
.
-
-
Pour plus d'informations sur le fonctionnement des index secondaires, consultez Améliorer l'accès aux données grâce aux index secondaires dans DynamoDB.
2.2 : application en action (procédure pas à pas de code)
Cette application a deux pages principales :
-
Page d'accueil — Cette page fournit à l'utilisateur un identifiant simple, un CREATEbouton pour créer un nouveau tic-tac-toe jeu, une liste des parties en cours, un historique des parties et toutes les invitations à des jeux en attente.
La page d'accueil n'est pas actualisée automatiquement. Vous devez actualiser la page pour actualiser les listes.
-
Page de jeu — Cette page montre la tic-tac-toe grille sur laquelle les utilisateurs jouent.
L'application met à jour la page de jeu automatiquement chaque seconde. JavaScript Dans votre navigateur, le serveur Web Python appelle le serveur Web Python toutes les secondes pour demander à la table Games si les éléments du jeu de la table ont changé. Si tel est le cas, JavaScript déclenche une actualisation de la page afin que l'utilisateur puisse voir le tableau mis à jour.
Nous verrons en détails le mode de fonctionnement de l'application.
Page d'accueil
Une fois l'utilisateur connecté, l'application affiche les trois listes d'informations suivantes :
-
Invitations – Cette liste affiche jusqu'aux 10 dernières invitations d'autres personnes, qui sont en attente d'acceptation par l'utilisateur connecté. Dans la capture d'écran précédente, user1 dispose d'invitations d'user5 et d'user2 en attente.
-
Games in-progress – Cette liste affiche jusqu'aux 10 dernière parties en cours. Il s'agit de parties auxquelles l'utilisateur participe activement et qui ont le statut
IN_PROGRESS
. Sur la capture d'écran, l'utilisateur1 joue activement à un tic-tac-toe jeu avec utilisateur3 et utilisateur4. -
Recent history – Cette liste affiche jusqu'aux 10 dernières parties que l'utilisateur a terminées, dont le statut est
FINISHED
. Dans la partie illustrée dans la capture d'écran, user1 a joué avec user2. Pour chaque partie terminée, la liste présente le résultat.
Dans le code, la fonction index
(dans application.py
) effectue les trois appels suivants pour récupérer des informations sur le statut du jeu :
inviteGames = controller.getGameInvites(session["username"]) inProgressGames = controller.getGamesWithStatus(session["username"], "IN_PROGRESS") finishedGames = controller.getGamesWithStatus(session["username"], "FINISHED")
Chacun de ces appels renvoie une liste d'éléments de DynamoDB qui sont encapsulés par les objets Game
. Il est facile d'extraire des données de ces objets dans la vue. La fonction d'index transmet ces listes d'objets à la vue pour qu'elle affiche leHTML.
return render_template("index.html", user=session["username"], invites=inviteGames, inprogress=inProgressGames, finished=finishedGames)
L' Tic-Tac-Toeapplication définit la Game
classe principalement pour stocker les données de jeu extraites de DynamoDB. Ces fonctions renvoient des listes d'objets Game
qui vous permettent d'isoler le reste de l'application du code relatif aux éléments Amazon DynamoDB. Par conséquent, ces fonctions vous aident à découpler le code de votre application à partir des détails de la couche de stockage de données.
Le modèle architectural décrit ici est également appelé modèle d'interface utilisateur model-view-controller (MVC). Dans ce cas, les instances de l'Game
objet (représentant les données) sont le modèle et la HTML page est la vue. Le contrôleur est divisé en deux fichiers. Le fichier application.py
a la logique de contrôleur pour la structure Flask, et la logique métier est isolée dans le fichier gameController.py
. C'est-à-dire que l'application stocke tout ce qui a trait à SDK DynamoDB dans son propre fichier séparé dans le dossier. dynamodb
Permettez-nous de passer en revue les trois fonctions et comment elles interrogent la table Games à l'aide des index secondaires globaux pour récupérer les données concernés.
Utilisation getGameInvites pour obtenir la liste des invitations à des jeux en attente
La fonction getGameInvites
récupère la liste des 10 dernières invitations en suspens. Ces jeux ont été créés par des utilisateurs, mais les adversaires n'ont pas accepté les invitations à jouer. Pour ces jeux, l'état reste PENDING
jusqu'à ce que l'adversaire accepte l'invitation. Si l'adversaire décline l'invitation, l'application supprime l'élément correspondant de la table.
La fonction spécifie la requête comme suit :
-
Elle spécifie l'index
OpponentId-StatusDate-index
à utiliser avec les valeurs de clés d'index et les opérateurs de comparaison suivants :-
La clé de partition est
OpponentId
et prend la clé d'index
.user ID
-
La clé de tri est
StatusDate
et prend l'opérateur de comparaison et la valeur de clé d'indexbeginswith="PENDING_"
.
Vous utilisez l'index
OpponentId-StatusDate-index
pour récupérer les jeux auxquels l'utilisateur connecté est invité, c'est-à-dire où l'utilisateur connecté est l'adversaire. -
-
La requête limite le résultat à 10 éléments.
gameInvitesIndex = self.cm.getGamesTable().query( Opponent__eq=user, StatusDate__beginswith="PENDING_", index="OpponentId-StatusDate-index", limit=10)
Dans l'index, pour chaque OpponentId
(clé de partition), DynamoDB conserve les éléments triés par StatusDate
(clé de tri). Par conséquent, les parties que la requête renvoie seront les 10 parties les plus récentes.
Utiliser getGamesWith le statut pour obtenir la liste des jeux ayant un statut spécifique
Une fois qu'un adversaire accepte une invitation, le statut du jeu passe sur IN_PROGRESS
. Une fois que le jeu se termine, le statut passe sur FINISHED
.
Les requêtes pour trouver des jeux qui sont en cours ou terminés sont identiques, à l'exception de la valeur du statut qui est différente. Par conséquent, l'application définit la fonction getGamesWithStatus
, qui prend la valeur de statut comme paramètre.
inProgressGames = controller.getGamesWithStatus(session["username"], "IN_PROGRESS") finishedGames = controller.getGamesWithStatus(session["username"], "FINISHED")
La section suivante décrit les jeux en cours, mais la même description s'applique également aux jeux terminés.
Une liste de jeux en cours pour un utilisateur donné comprend les deux éléments suivants :
-
Jeux en cours hébergés par l'utilisateur
-
Jeux en cours où l'utilisateur est l'adversaire
La fonction getGamesWithStatus
exécute les deux requêtes suivantes, chaque fois à l'aide de l'index secondaire approprié.
-
La fonction interroge la table
Games
en utilisant l'indexHostId-StatusDate-index
. Pour l'index, la requête spécifie les valeurs de clés primaires, clé de partition (HostId
) et clé de tri (StatusDate
), ainsi que les opérateurs de comparaison.hostGamesInProgress = self.cm.getGamesTable ().query(HostId__eq=user, StatusDate__beginswith=status, index="HostId-StatusDate-index", limit=10)
Notez la syntaxe Python pour les opérateurs de comparaison :
-
HostId__eq=user
spécifie l'opérateur de comparaison d'égalité. -
StatusDate__beginswith=status
spécifie l'opérateur de comparaisonBEGINS_WITH
.
-
-
La fonction interroge la table
Games
en utilisant l'indexOpponentId-StatusDate-index
.oppGamesInProgress = self.cm.getGamesTable().query(Opponent__eq=user, StatusDate__beginswith=status, index="OpponentId-StatusDate-index", limit=10)
-
Ensuite, la fonction combine les deux listes, trie et pour les premiers 0 à 10 éléments, elle crée une liste des objets
Game
et renvoie la liste à la fonction d'appel (à savoir, l'index).games = self.mergeQueries(hostGamesInProgress, oppGamesInProgress) return games
Page de jeu
La page de jeu est l'endroit où l'utilisateur joue à tic-tac-toe des jeux. Elle présente la grille de jeu ainsi que des informations relatives au jeu. La capture d'écran suivante illustre un exemple de jeu en cours :
L'application affiche la page de jeu dans les cas suivants :
-
L'utilisateur crée un jeu en invitant un autre utilisateur à jouer.
Dans ce cas, la page affiche l'utilisateur comme hôte et le statut de jeu comme
PENDING
, en attendant que l'adversaire accepte. -
L'utilisateur accepte l'une des invitations en attente sur la page d'accueil.
Dans ce cas, la page affiche l'utilisateur comme adversaire et le statut du jeu comme
IN_PROGRESS
.
Une sélection d'utilisateur sur le plateau génère une demande POST
de formulaire à l'application. C'est-à-dire que Flask appelle la selectSquare
fonction (inapplication.py
) avec les données du HTML formulaire. Cette fonction, à son tour, appelle la fonction updateBoardAndTurn
(dans gameController.py
) pour mettre à jour l'élément de jeu comme suit :
-
Elle ajoute un nouvel attribut spécifique au déplacement.
-
Elle met à jour la valeur d'attribut
Turn
pour l'utilisateur qui jouera le prochain coup.
controller.updateBoardAndTurn(item, value, session["username"])
La fonction renvoie la valeur true si la mise à jour de l'élément a réussi ; sinon, elle renvoie la valeur false. Notez les éléments suivants sur la fonction updateBoardAndTurn
:
-
La fonction appelle la
update_item
fonction SDK for Python pour effectuer un ensemble fini de mises à jour d'un élément existant. La fonction mappe à l'opérationUpdateItem
dans DynamoDB. Pour plus d'informations, consultez UpdateItem.Note
La différence entre les opérations
UpdateItem
etPutItem
est quePutItem
remplace l'élément entier. Pour plus d'informations, consultez PutItem.
Pour l'appel update_item
, le code identifie les éléments suivants :
-
La clé primaire de la table
Games
(à savoir,ItemId
).key = { "GameId" : { "S" : gameId } }
-
Le nouvel attribut à ajouter, spécifique au déplacement de l'utilisateur en cours et sa valeur (par exemple,
TopLeft="X"
).attributeUpdates = { position : { "Action" : "PUT", "Value" : { "S" : representation } } }
-
Conditions qui doivent avoir une valeur true pour que la mise à jour ait lieu :
-
La partie doit être en cours. C'est à dire que la valeur d'attribut
StatusDate
doit commencer parIN_PROGRESS
. -
Le tour actuel doit être un tour d'utilisateur valide comme indiqué par l'attribut
Turn
. -
L'emplacement que l'utilisateur choisit doit être disponible. Autrement dit, l'attribut correspondant à l'emplacement ne doit pas exister.
expectations = {"StatusDate" : {"AttributeValueList": [{"S" : "IN_PROGRESS_"}], "ComparisonOperator": "BEGINS_WITH"}, "Turn" : {"Value" : {"S" : current_player}}, position : {"Exists" : False}}
-
Maintenant, la fonction appelle update_item
pour mettre à jour l'élément.
self.cm.db.update_item("Games", key=key, attribute_updates=attributeUpdates, expected=expectations)
Après le renvoi de la fonction, les appels de la fonction selectSquare
sont redirigés, comme illustré dans l'exemple suivant.
redirect("/game="+gameId)
Cet appel permet au navigateur de s'actualiser. Dans le cadre de cette actualisation, l'application vérifie si la partie s'est terminée par une victoire ou un nul. Si c'est le cas, l'application met à jour l'élément de partie en conséquence.