PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Как да запиша ежедневно класиране за модел в Django?

Бих предложил нещо подобно на това, което e4c5 предложи , но също така бих:

  • Генерирайте индекс за датата на класирането, така че получаването на всички рангове за всеки един ден да може да бъде оптимизирано.

  • Маркирайте датата и ученика като unique_together . Това предотвратява възможността за записване на две оценки за един и същи ученик на една и съща дата.

Моделите ще изглеждат така:

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Каква е разликата между Postgres DISTINCT срещу DISTINCT ON?

  2. Референтен psql параметър в анонимния блок на PL/pgSQL

  3. Ескейпирането на hstore съдържа оператори в JDBC подготвен оператор

  4. Как мога да гарантирам, че материализираният изглед винаги е актуален?

  5. как да препратка към променлива на схема в plpgsql