Ik zou iets voorstellen dat lijkt op wat e4c5 suggereerde , maar ik zou ook:
-
Genereer een index op de datum van de rangen zodat het verkrijgen van alle rangen op een enkele dag kan worden geoptimaliseerd.
-
Markeer de datum en leerling als
unique_together
. Dit voorkomt de mogelijkheid om twee rangen voor dezelfde student op dezelfde datum vast te leggen.
De modellen zouden er als volgt uitzien:
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()
In een volwaardige applicatie zou ik ook enige uniciteitsbeperkingen verwachten op Grade
en Student
maar het probleem in de vraag geeft niet genoeg details over deze modellen.
Je zou dan elke dag een taak kunnen uitvoeren met cron
of welke taakbeheerder je ook wilt gebruiken (Celery is ook een optie), om een commando als het volgende uit te voeren dat de rangen zou bijwerken volgens een bepaalde berekening en de oude records zou opschonen. De volgende code is een illustratie van hoe het kan. De echte code moet zo worden ontworpen dat deze over het algemeen idempotent is (de volgende code is niet omdat de rangberekening willekeurig is), zodat als de server opnieuw wordt opgestart tijdens een update, de opdracht gewoon opnieuw kan worden uitgevoerd. Hier is de code:
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()
Waarom geen augurken?
Meerdere redenen:
-
Het is een voortijdige optimalisatie en over het algemeen waarschijnlijk helemaal geen optimalisatie. Sommige bewerkingen kunnen sneller zijn, maar andere bewerkingen langzamer zal zijn. Als de rangen worden gepickt in een veld op
Student
dan betekent het laden van een specifieke student in het geheugen dat alle ranginformatie samen met die student in het geheugen wordt geladen. Dit kan worden verholpen door.values()
. te gebruiken of.values_list()
maar dan krijg je geenStudent
meer exemplaren uit de database. Waarom hebbenStudent
instanties in de eerste plaats en niet alleen toegang tot de onbewerkte database? -
Als ik de velden verander in
Rank
, maken Django's migratiefaciliteiten het gemakkelijk om de benodigde wijzigingen door te voeren wanneer ik de nieuwe versie van mijn applicatie implementeer. Als de ranginformatie in een veld wordt gepickt, moet ik elke structuurwijziging beheren door aangepaste code te schrijven. -
De databasesoftware heeft geen toegang tot waarden in een augurk en daarom moet u aangepaste code schrijven om toegang te krijgen. Als u met het bovenstaande model studenten per rang wilt weergeven (en de rangorde voor vandaag is al berekend), dan kunt u het volgende doen:
for r in Rank.objects.filter(date=utcnow()).order_by("value")\ .prefetch_related(): print r.student.name
Als je augurken gebruikt, moet je alle
Students
scan scannen en maak de rangen los om degene voor de gewenste dag te extraheren, en gebruik vervolgens een Python-gegevensstructuur om de studenten op rang te ordenen. Zodra dit is gebeurd, moet u deze structuur herhalen om de namen op volgorde te krijgen.