sql >> データベース >  >> RDS >> PostgreSQL

Djangoでモデルの毎日のランキングを記録するにはどうすればよいですか?

    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()
    

    ピクルスにしないのはなぜですか?

    複数の理由:

    1. これは時期尚早の最適化であり、全体としてはおそらくまったく最適化ではありません。 いくつか 操作は高速かもしれませんが、その他の操作 遅くなります。ランクがStudentのフィールドにピクルスされている場合 次に、特定の学生をメモリにロードするということは、その学生と一緒にすべてのランク情報をメモリにロードすることを意味します。これは、.values()を使用することで軽減できます。 または.values_list() しかし、その後、Studentを取得できなくなります。 データベースからのインスタンス。なぜStudent そもそもインスタンスであり、生のデータベースにアクセスするだけではありませんか?

    2. Rankのフィールドを変更した場合 、Djangoの移行機能を使用すると、アプリケーションの新しいバージョンをデプロイするときに、必要な変更を簡単に実行できます。ランク情報がフィールドに組み込まれている場合は、カスタムコードを記述して構造の変更を管理する必要があります。

    3. データベースソフトウェアはピクルスの値にアクセスできないため、それらにアクセスするにはカスタムコードを作成する必要があります。上記のモデルで、今日のランク別に学生を一覧表示する場合(および、今日のランクはすでに計算されている場合)、次のことができます。

      for r in Rank.objects.filter(date=utcnow()).order_by("value")\
          .prefetch_related():
          print r.student.name
      

      きゅうりのピクルスを使用する場合は、すべてのStudentsをスキャンする必要があります ランクを選択解除して希望の日にランクを抽出し、Pythonデータ構造を使用して生徒をランク別に並べ替えます。これが完了したら、名前を順番に取得するために、この構造を反復処理する必要があります。



    1. mysqlにトランザクションを含む複数のテーブルを挿入する

    2. スレッドメインの例外com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:SQL構文にエラーがあります

    3. SQL Serverで行を列に変換するにはどうすればよいですか?

    4. プリペアドステートメントで''(タイムスタンプ)付きの文字列を渡す方法は?