gpt4 book ai didi

python - 如何有效地在 Django 中存储对象的排名列表?

转载 作者:可可西里 更新时间:2023-11-01 08:44:43 27 4
gpt4 key购买 nike

我有一个 Django 模型:

from django.db import models

class Player(models.Model):
name = models.CharField(max_length=254, null=True, blank=True,)
score = models.IntegerField()

A = Player.create(name="A", score=99)
B = Player.create(name="B", score=66)
C = Player.create(name="C", score=66)
D = Player.create(name="D", score=55)
E = Player.create(name="E", score=44)

我想按分数维护所有玩家的排名。如果玩家得分相同,则他们将获得相同的排名。所以在这种情况下,排名将如下所示:

Name       Score     Rank
A 99 1
B 66 2
C 66 2
D 55 4
E 44 5

我想将此排名存储在数据库中,这样我就不必经常执行昂贵的排序查询。我需要高效地执行以下所有操作:

  1. 给定一个玩家,查询他们的排名
  2. 给定一个排名,找出哪些玩家拥有该排名
  3. 给定一个玩家,将他们插入到这个排名中
  4. 给定一个玩家,将他们从这个排名中删除
  5. 给定一个球员和一个分数,更新他们在这个排名中的位置

我需要在此列表中插入和删除玩家。每当我执行#3、#4 或#5 时,我都需要相应地更新其他玩家的排名以保持排名的完整性。

在 Django 中最有效的方法是什么?我如何构建我的模型,这样才能有效地工作并且我的数据库操作将最少?请告诉我任何新模型应该是什么样子。

最佳答案

您可以具体化 ranks 并在保存 Player 时重新排序,请注意,并非每次保存新分数时都需要重新排序:

新模型:

class ScoreRank(models.Model):
score = models.IntegerField(primary_key=True)
rank = models.IntegerField()
player_count = models.IntegerField()

保持排名排序:

from django.db.models.signals import pre_save
@receiver(pre_save, sender=Player)
def update_score_rank(sender, instance, **kwargs):
#delete from previous rank
if instance.pk:
previous_score = ( Player.objects
.filter( id=instance.id )
.values_list( 'score', flat=True ).first() )
sc = ScoreRank.objects.get( score = previous_score )
if sc.player_count == 1:
#new hole in ranks, add -1 to other ranks to remove it:
_ = (ScoreRank.objects
.filter( score__gt = previous_score )
.update( rank=F('rank') - 1 ) )
sc.delete()
#insert in new rank
sc, is_new = ( ScoreRank.objects
.get_or_create(score=instance.score,
defaults={'rank': -1,'player_count': 1,}) )
if not is_new:
#this score is not new: add one to player_count
_ = ( ScoreRank.objects
.filter( score = instance.score )
.update( rank=F('player_count') + 1 ) )
else:
#this score is not new: make hole for it
rank = ( ScoreRank.objects
.filter( score__gt = instance.score )
.annotate( m=Min("score" ) ) )
new_rank = rank["m"] if rank["m"] else 1
_ = ( ScoreRank.objects
.filter( score__lte = new_rank )
.update( rank=F('rank') + 1 ) )
_ = ( ScoreRank.objects
.filter( sc = sc.score )
.update( rank=new_rank ) )

不要忘记将数据库操作包含在单个事务(可序列化事务)中

免责声明:未经测试。

关于python - 如何有效地在 Django 中存储对象的排名列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32034074/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com