Je crée un site similaire à Reddit et Hacker News qui possède une base de données de liens et de votes. Je mettant en place des informations sur la pirate de pirate de la popularité et que les choses se passent joliment jusqu'à ce qu'il arrive à recueillir ces liens et à les afficher. L'algorithme est simple:
TemplateSyntaxError at / Caught an exception while rendering: column "links_link.id" must appear in the GROUP BY clause or be used in an aggregate function LINE 1: ...karma_delta) - 1) / POW(2, 1.5)) AS "popularity", "links_lin...
4 Réponses :
sur les nouvelles du pirate informatique, seules les 210 dernières histoires et 210 histoires les plus populaires sont paginées (7 pages d'une valeur de 30 étages chacune). Je suppose que la raison de la limite (au moins en partie) est ce problème. P>
Pourquoi ne pas laisser tomber tout le SQL de fantaisie pour les histoires les plus populaires et gardez simplement une liste d'exécution à la place? Une fois que vous avez établi une liste des 210 top 210, il vous suffit de vous soucier de la réorganisation lorsqu'un nouveau vote est arrivé depuis que l'ordre relatif est maintenu au fil du temps. Et quand un nouveau vote est arrivé, il vous suffit de vous soucier de la réorganisation de l'histoire qui a reçu le vote. P>
Si l'histoire qui a reçu le vote n'est pas sur la liste, calculez le score de cette histoire, plus l'histoire la moins populaire que est em> sur la liste. Si l'histoire qui a reçu le vote est plus faible, vous avez terminé. Si c'est plus élevé, calculez le score actuel pour le deuxième à au moins le plus populaire (histoire 209) et comparer à nouveau. Continuez à travailler jusqu'à ce que vous trouviez une histoire avec un score plus élevé, puis placez l'histoire nouvellement votée à droite ci-dessous celui-ci dans le classement. Sauf si, bien sûr, il atteint le n ° 1. P>
L'avantage de cette approche est qu'il limite l'ensemble des histoires que vous devez regarder pour comprendre la liste des principales histoires. Dans le pire des cas absolu, vous devez calculer le classement pour 211 histoires. Il est donc très efficace que si vous devez établir la liste d'un ensemble de données existant - mais ce n'est qu'une pénalité ponctuelle en supposant que vous mettez en cache la liste de la liste. P>
Les bowvotes sont un autre problème, mais je ne peux que uppoter (au niveau de mon karma, de toute façon). P>
C'est une jolie idée astucieuse. Je ne m'attends jamais à ce que ce site devienne très gros, il faudrait donc avoir une modification majeure de ces chiffres, mais j'aime bien où ça va.
Quelques mois de retard mais je suis de retour à cela. Cela ne vous dérangerait pas d'élaborer sur cette autre? Comment garder la trace de votre liste de course? Une autre table de base de données? Serait-il calculé à la volée sur chaque demande HTTP? Ne vous inquiétez pas des bowvotes, je suis arrivé à la conclusion que la descente est une mauvaise idée dans la plupart des cas. Le bâtimenttraputation.com a de bonnes lectures.
popular_links = Link.objects.select_related()
popular_links = popular_links.extra(
select = {
'karma_total': 'SUM(vote.karma_delta)',
'popularity': '(karma_total - 1) / POW(2, 1.5)'
},
order_by = ['-popularity']
)
Or select some sane number, sort the selection using python in any way you like, and cache if its going to be static for all users which it looks like it will - set cache expiration to a minute or so.But the extra will work better for paginated results in a highly dynamic setup.
Je pense vraiment que c'est ce que je vais faire ce que je vais, bien que pour une raison quelconque, j'obtiens continuellement la même erreur de: attrapé une exception lors de la rendu: la colonne "karma_total" n'existe pas la ligne 1: SELECT ((KARMA_TOTAL - 1) / POW ( 2, 1.5)) "Popularité", (S ... qui est étrange parce que je pensais que karma_total était déjà défini juste une ligne au-dessus de cela!
Bien juste le remplacer alors si vous n'en avez pas besoin dans le résultat final: 'Popularité': '(Somme (vote.karma_delta) - 1) / POW (2, 1.5)' Code>
Homme, c'est la réponse particulière que je souhaite travailler le plus. Les autres réponses sont excellentes mais je veux que celui-ci fonctionne. Attrapé une exception lors de la rendu: entrée de la clause manquante pour la table "vote" de la ligne 1: Sélectionnez (((((((Vott.karma_total - 1) / POW (2, 1.5)) Comme "Popularité ... est mon dernière erreur. Ce ne serait pas" Ça a quelque chose à voir avec mon utilisation de 1.1.1 au lieu de la version de développement serait-ce?
Votre table de vote n'est pas ajoutée à la requête par Select_Related; Vous pouvez l'ajouter manuellement en modifiant des tables supplémentaires = ['vote'] code> si votre table de votes s'appelle vote code>
Voir mon code edit 3. Je suis si proche que je peux goûter! Je reçois une erreur faisant référence au fait que je n'ai pas les valeurs appropriées dans mon groupe. Je ne sais pas comment les ajouter à ce que Django a généralement pris soin de cela.
Pourquoi avez-vous besoin de liens_link là-bas? Vous pouvez ajouter un groupe en ajoutant la dernière ligne à ceci, populaire_links.query.group_by = 'link_link.id' code> Si vous êtes sûr que vous voulez ce que vous voulez
semble que vous puissiez surcharger le code> de la classe code> vote code> et devez-la mettre à jour le lien de cette façon, chaque fois que vous appelez un link_o.save () ou vote_o.save (), il ré-calculera la popularité. Vous devez être un peu prudent parce que lorsque vous appelez de cette façon, il ne chargera qu'un seul objet de lien dans la mémoire à la fois ... Donc, si vous avez une base de données géante, il ne va pas provoquer une erreur de mémoire. P> Maintenant pour faire votre classement Tout ce que vous avez à faire est de: P> correspondant code> objet. Quelque chose comme ça devrait bien fonctionner: link.Object.All (). Mise à jour ('Mise à jour de quelque chose') code> Il n'appellera pas notre surchargé () code > fonction. Donc, lorsque j'utilise ce genre de chose, je crée une commande de gestion qui met à jour tous les objets afin qu'ils ne soient pas trop obsolètes. Quelque chose comme ça fonctionnera merveilleusement: p> Link.objects.all().order_by('-popularity')
Cela signifie-t-il que chaque fois qu'un lien est voté, chaque ligne de liaison est mise à jour?
non ... il ne ferait que mettre à jour le lien qui a été voté sur ... donc ce ne serait donc pas si intensif du processeur
Voici la réponse finale à ma question bien que plusieurs mois de retard et pas exactement ce que j'avais à l'esprit. J'espère que cela sera utile à certains.
def hot(request):
links = Link.objects.select_related().annotate(votes=Count('vote')).order_by('-created')[:150]
for link in links:
delta_in_hours = (int(datetime.now().strftime("%s")) - int(link.created.strftime("%s"))) / 3600
link.popularity = ((link.votes - 1) / (delta_in_hours + 2)**1.5)
links = sorted(links, key=lambda x: x.popularity, reverse=True)
links = paginate(request, links, 5)
return direct_to_template(
request,
template = 'links/link_list.html',
extra_context = {
'links': links
})
En tant que Sidenote, il existe un moyen plus facile de calculer delta_in_hours à l'aide de DateTime.Timedelta: (datetime.now () - link.Créé) .Total_seconds () / 3600
Hmm, a mangé mah html. Ah bien, moins de mes soucis.