Eu sugeriria algo semelhante ao que e4c5 sugeriu , mas eu também:
-
Gere um índice na data das classificações para que a obtenção de todas as classificações em um único dia possa ser otimizada.
-
Marque a data e o aluno comounique_together
. Isso impede a possibilidade de registrar duas classificações para o mesmo aluno na mesma data.
Os modelos ficariam assim:
from django.db import models
class Grade(models.Model):
pass # Whatever you need here...
class Student(models.Model):
name = models.CharField(max_length=20)
grade = models.ForeignKey(Grade)
class Rank(models.Model):
class Meta(object):
unique_together = (("date", "student"), )
date = models.DateField(db_index=True)
student = models.ForeignKey(Student)
value = models.IntegerField()
Em um aplicativo completo, eu também esperaria ter algumas restrições de exclusividade em
Grade
e Student
mas o problema apresentado na pergunta não fornece detalhes suficientes sobre esses modelos. Você poderia então executar uma tarefa todos os dias com
cron
ou qualquer gerenciador de tarefas que você queira usar (Aipo também é uma opção), para executar um comando como o seguinte que atualizaria as classificações de acordo com algum cálculo e limparia os registros antigos. O código a seguir é uma ilustração de como isso pode ser feito. O código real deve ser projetado para ser geralmente idempotente (o código a seguir não é porque o cálculo de classificação é aleatório) para que, se o servidor for reinicializado no meio de uma atualização, o comando possa ser executado novamente. Aqui está o código:import random
import datetime
from optparse import make_option
from django.utils.timezone import utc
from django.core.management.base import BaseCommand
from school.models import Rank, Student
def utcnow():
return datetime.datetime.utcnow().replace(tzinfo=utc)
class Command(BaseCommand):
help = "Compute ranks and cull the old ones"
option_list = BaseCommand.option_list + (
make_option('--fake-now',
default=None,
help='Fake the now value to X days ago.'),
)
def handle(self, *args, **options):
now = utcnow()
fake_now = options["fake_now"]
if fake_now is not None:
now -= datetime.timedelta(days=int(fake_now))
print "Setting now to: ", now
for student in Student.objects.all():
# This simulates a rank computation for the purpose of
# illustration.
rank_value = random.randint(1, 1000)
try:
rank = Rank.objects.get(student=student, date=now)
except Rank.DoesNotExist:
rank = Rank(
student=student, date=now)
rank.value = rank_value
rank.save()
# Delete all ranks older than 180 days.
Rank.objects.filter(
date__lt=now - datetime.timedelta(days=180)).delete()
Por que não picles?
Vários motivos:
-
É uma otimização prematura e, em geral, provavelmente não é uma otimização. Alguns as operações podem ser mais rápidas, mas outras operações será mais lento. Se as classificações forem selecionadas em um campo emStudent
então, carregar um aluno específico na memória significa carregar todas as informações de classificação na memória junto com esse aluno. Isso pode ser mitigado usando.values()
ou.values_list()
mas você não está mais recebendoStudent
instâncias do banco de dados. Por queStudent
instâncias em primeiro lugar e não apenas acessar o banco de dados bruto?
-
Se eu alterar os campos emRank
, as facilidades de migração do Django permitem facilmente realizar as mudanças necessárias quando eu implemento a nova versão do meu aplicativo. Se as informações de classificação forem armazenadas em um campo, tenho que gerenciar qualquer alteração de estrutura escrevendo código personalizado.
-
O software de banco de dados não pode acessar valores em um pickle e, portanto, você precisa escrever um código personalizado para acessá-los. Com o modelo acima, se você deseja listar os alunos por classificação hoje (e as classificações de hoje já foram calculadas), você pode fazer:
for r in Rank.objects.filter(date=utcnow()).order_by("value")\ .prefetch_related(): print r.student.name
Se você usa picles, precisa escanear todos osStudents
e descompacte as classificações para extrair a do dia desejado e, em seguida, use uma estrutura de dados Python para ordenar os alunos por classificação. Feito isso, você precisa iterar sobre essa estrutura para obter os nomes em ordem.