Système de Badge : projet du mois !
Bonjour :)
Je suis en train de me faire mon système de Badges.
Ci-dessous une méthode qui gère les ajouts (ou pas) des badges au compte forum de l'utilisateur.
Cette méthode je vais la mettre dans la vue Index des forums
Comme ça les badges seront actualisés quand l'utilisateur accèdera à l'index.
ça parait être compliqué ? énergivore en ressources ? lol
Perso je suis content du système ça fonctionne bien !
Merci d'avance
def badge_manager(self):
messages_10 = Badge.objects.get(description="10 messages")
messages_50 = Badge.objects.get(description="50 messages")
messages_100 = Badge.objects.get(description="100 messages")
new = Badge.objects.get(description="Nouveau")
likes_10 = Badge.objects.get(description="10 likes")
likes_50 = Badge.objects.get(description="50 likes")
likes_100 = Badge.objects.get(description="100 likes")
forum_master = Badge.objects.get(description="Forum Master")
if Message.objects.filter(account=self).count() >= 10 and messages_10 not in self.badges.all():
self.badges.add(messages_10)
if Message.objects.filter(account=self).count() >= 50 and messages_50 not in self.badges.all():
self.badges.add(messages_50)
if Message.objects.filter(account=self).count() >= 100 and messages_100 not in self.badges.all():
self.badges.add(messages_100)
if timezone.now().date() - self.joined < timedelta(days=4) and new not in self.badges.all():
self.badges.add(new)
if self.forum_master and forum_master not in self.badges.all():
self.badges.add(forum_master)
Salut Gab !
Effectivement c'est une bonne question à commencer à se poser, le cas de l'optimisation. Pour mieux déboguer tout ça je te conseille d'installer le package Django Debug Toolbar. Ça te permet d'avoir un aperçu de toutes les requêtes qui sont effectuées vers ta base de données. Dans ton cas, il devrait t'indiquer que tu as de nombreuses requêtes similaires, notamment quand tu récupères les messages.
C'est la chose la plus facile à optimiser dans ton code, et c'est valable au-delà de Django : il faut rester "DRY" (Don't Repeat Yourself).
Stock le résultat dans une variable et réutilise-le, tu passes déjà avec ça de 3 requêtes exactement identiques à une seule.
number_of_messages = Message.objects.filter(account=self).count()
Sinon tu peux améliorer le code en évitant de récupérer chaque badge séparément et en évitant la suite de if avec un dictionnaire :
from django.db.models import Count
def badge_manager(self):
# Je récupère tous les badges en une requête
badges = Badge.objects.filter(description__in=["10 messages", "50 messages", "100 messages", "Nouveau", "Forum Master"])
# Je récupère les badges que l'utilisateur a déjà
user_badges = self.badges.all()
# Une seule requête à la BDD
number_of_messages = Message.objects.filter(account=self).count()
# Je crée un dictionnaire pour faire correspondre les descriptions des badges aux conditions d'attribution
badge_conditions = {
"10 messages": message_count >= 10,
"50 messages": message_count >= 50,
"100 messages": message_count >= 100,
"Nouveau": timezone.now().date() - self.joined < timedelta(days=4),
"Forum Master": self.forum_master,
}
# On boucle sur tous les badges et leur condition d'obtention
for description, condition in badge_conditions.items():
if condition: # Si la condition est validée, on récupère le badge
badge, _ = Badge.objects.get_or_create(description=description)
if badge not in user_badges: # Si l'utilisateur ne l'a pas déjà, on lui ajoute
self.badges.add(badge)
Il faudra probablement adapter ton code, je n'ai pas le code de ton modèle Badge, tu peux peut-être simplifier la boucle en fonction de comment est fait ton modèle.
Aussi je me suis basé sur la description pour le dictionnaire badge_conditions, tu pourrais aussi passer par le pk ou un autre attribut qui serait réellement unique (même si j'imagine que la description sera unique à chaque badge).
C'est juste un exemple de ce que tu peux faire, l'idée est surtout de réduire le nombre de requêtes similaires (ici avec le number_of_messages et la récupération de tous les badges en une seule requête, tu divises par 5 au moins le nombre de requêtes).
Et même au niveau de la conception tu peux imaginer déplacer ton code ailleurs que dans le dashboard. Tu pourrais par exemple faire cette vérification quand quelqu'un poste un message (et faire les vérifications spécifiques aux badges portants sur le nombre de messages), etc.
Dans le dashboard c'est pas mal si tu ne les affiche nul part ailleurs, ça permet d'alléger le code et ne pas faire des vérifications à chaque fois que quelqu'un poste un message.
Après tu pourrais aussi faire un cronjob qui fait les vérifications pour tout le monde 1 seule fois par jour si tu n'as pas besoin d'avoir quelque chose d'ultra réactif, ça permettrait d'alléger le dashboard.
Après c'est une question de choix, ça reste quand même assez léger, on parle de 3-4 requêtes, mais c'est bien de commencer à penser à ça quand même, le nombre de badge peut rapidement augmenter et tu peux te retrouver sans l'avoir prévu avec des problèmes de performances "down the line" comme on dit en bon français ^^
Super Merci Thibault !
EN général je me débrouille pour bien gérer mes requêtes mais là je sentais que j'étais faiblard ! lol
Effectivement, les vérifications je ne les fait pas à chaque post de messages, mais dans l'index, comme ça dès que l'utilisateur arrive sur le forum ça réactualise.
Merci encore en tous cas !
Les cronjob... faut que je regarde comment je peux faire j'avais regardé une fois mais pas trop compris :s
Merci bcq en tous cas !
Inscris-toi
(c'est gratuit !)
Tu dois créer un compte pour participer aux discussions.
Créer un compte