e4c5 提案 に似たものを提案します 、しかし私もそうします:
-
ランクの日付にインデックスを生成して、1日にすべてのランクを取得することを最適化できるようにします。
-
日付と生徒を
unique_together
としてマークします 。これにより、同じ生徒の2つのランクを同じ日に記録する可能性がなくなります。
モデルは次のようになります:
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()
本格的なアプリケーションでは、Grade
にいくつかの一意性の制約があることも期待します。 およびStudent
しかし、質問で提示された問題は、これらのモデルに関する十分な詳細を提供していません。
その後、cron
を使用して毎日タスクを実行できます。 または、使用するタスクマネージャー(Celeryもオプション)を使用して、次のようなコマンドを実行し、計算に従ってランクを更新し、古いレコードを削除します。次のコードはイラストです。 それがどのように行われることができるかについて。実際のコードは、更新の途中でサーバーが再起動された場合にコマンドを再実行できるように、一般的にべき等になるように設計する必要があります(次のコードはランク計算がランダムであるためではありません)。コードは次のとおりです:
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()
ピクルスにしないのはなぜですか?
複数の理由:
-
これは時期尚早の最適化であり、全体としてはおそらくまったく最適化ではありません。 いくつか 操作は高速かもしれませんが、その他の操作 遅くなります。ランクが
Student
のフィールドにピクルスされている場合 次に、特定の学生をメモリにロードするということは、その学生と一緒にすべてのランク情報をメモリにロードすることを意味します。これは、.values()
を使用することで軽減できます。 または.values_list()
しかし、その後、Student
を取得できなくなります。 データベースからのインスタンス。なぜStudent
そもそもインスタンスであり、生のデータベースにアクセスするだけではありませんか? -
Rank
のフィールドを変更した場合 、Djangoの移行機能を使用すると、アプリケーションの新しいバージョンをデプロイするときに、必要な変更を簡単に実行できます。ランク情報がフィールドに組み込まれている場合は、カスタムコードを記述して構造の変更を管理する必要があります。 -
データベースソフトウェアはピクルスの値にアクセスできないため、それらにアクセスするにはカスタムコードを作成する必要があります。上記のモデルで、今日のランク別に学生を一覧表示する場合(および、今日のランクはすでに計算されている場合)、次のことができます。
for r in Rank.objects.filter(date=utcnow()).order_by("value")\ .prefetch_related(): print r.student.name
きゅうりのピクルスを使用する場合は、すべての
Students
をスキャンする必要があります ランクを選択解除して希望の日にランクを抽出し、Pythonデータ構造を使用して生徒をランク別に並べ替えます。これが完了したら、名前を順番に取得するために、この構造を反復処理する必要があります。