如何在Django中记录模型的每日排名? [英] How do I record daily rankings for a model in Django?

查看:92
本文介绍了如何在Django中记录模型的每日排名?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模型,必须为该模型记录一个 PositiveSmallIntegerField ,该模型每天会根据相关得分进行更新。

I have a model to which I have to record a PositiveSmallIntegerField to the object, that is updated daily with the relevant score.

class Student(models.Model):
    name = models.CharField(max_length=20)
    grade = models.ForeignKey(Grade)
    rank = ??

使用此模型的对象数永远不会超过100,并且分数/等级必须保留期限为180天。数据库是Postgresql 9.2。

The number of objects with this model will never exceed 100 and the scores/ranks must be retained for a period of 180 days. The database is Postgresql 9.2.

排名是每天根据另一个应用的得分计算的,我想将其存储在与学生模型相关的数据库中,坚持模型设计,我不知道,该怎么做? Django中是否有重复字段?

The rank is calculated daily on the score from another app, which I want to store in the database related to the student model, where I'm stuck with the model design, I have no Idea, what should be done for the ranks? Is there a repeating field in Django?

任何线索或经验将不胜感激

Any clues or experiences will be much appreciated

谢谢。

数据库必须看起来像这样,

The database must look something like this,

+---------+-------+----------+----------+----------+----------+----------+----------+
| Student | Grade | 08-01-15 | 08-02-15 | 08-03-15 | 08-04-15 | 08-05-15 | 08-06-15 |
+---------+-------+----------+----------+----------+----------+----------+----------+
| Alex    |     5 |        2 |        1 |        1 |        2 |        3 |        2 |
| John    |     5 |        3 |        2 |        3 |        4 |        2 |        4 |
| Susan   |     5 |        1 |        4 |        2 |        1 |        1 |        1 |
| Zara    |     5 |        4 |        3 |        4 |        3 |        4 |        3 |
+---------+-------+----------+----------+----------+----------+----------+----------+

必须在此处显示的日期存储学生的排名,对于第1天,排名必须存储在列/类似的内容中,并且必须连续180天继续工作,必须将每天的排名添加到连续的天数中。

The rank of the student must be stored for the days like shown here, for the day 1, the ranks must be stored in a column/anything similar, and the number of days must go on for the consecutive 180 days, the ranks for each day must be added to the consecutive days.

我对保存并没有坚持方法,但有关要保存计算出的排名的字段。

I'm not stuck with the save method, but about the field where to save the calculated ranks.

推荐答案

我建议使用类似于e4c5 建议,但我也将:

I would suggest something similar to what e4c5 suggested, but I would also:


  • 在排名日期生成索引,以便

  • Generate an index on the date of the ranks so that obtaining all the ranks on any single day can be optimized.

将日期和学生标记为 unique_together 。这样可以避免在同一日期记录同一学生的两个等级。

Mark the date and student as unique_together. This prevents the possibility of recording two ranks for the same student on the same date.

模型看起来像这样:

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 和学生,但问题中提出的问题并未提供有关这些模型的足够详细信息。

In a full-fledged application I'd also expect to have some uniqueness constraints on Grade and Student but the problem presented in the question does not provide enough details about these models.

您可以每d运行一个任务用 cron 或任何您想使用的任务管理器(Celery也是一个选项)运行以下命令,该命令将根据一些计算来更新等级并清除旧唱片。以下代码是如何实现的说明。实际代码应设计为通常幂等的(以下代码不是因为排名计算是随机的),因此,如果在更新过程中重新引导服务器,则只需重新运行命令即可。这是代码:

You could then run a task every day with cron or whatever task manager you want to use (Celery is also an option), to run a command like the following that would update the ranks according to some computation and purge the old records. The following code is an illustration of how it can be done. The real code should be designed to be generally idempotent (the following code is not because the rank computation is random) so that if the server is rebooted in the middle of an update, the command can just be rerun. Here's the 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()



为什么不泡菜?



多个原因:

Why not pickles?

Multiple reasons:


  1. 这是一个过早的优化,总体上可能根本不是优化。 某些操作可能会更快,但其他操作会更慢。如果等级被腌制到 Student 上的字段中,则在内存中加载特定学生意味着将所有等级信息与该学生一起加载到内存中。可以通过使用 .values() .values_list()缓解这种情况,但是您再也不会得到<$数据库中的c $ c> Student 实例。为什么首先要有 Student 实例而不是仅访问原始数据库?

  1. It is a premature optimization, and overall probably not an optimization at all. Some operations may be faster, but other operations will be slower. If the ranks are pickled into a field on Student then, loading a specific student in memory means loading all the rank information into memory together with that student. This can be mitigated by using .values() or .values_list() but then you are no longer getting Student instances from the database. Why have Student instances in the first place and not just access the raw database?

如果我更改在 Rank 中的字段中,Django的迁移工具可以轻松地在我部署新版本的应用程序时执行所需的更改。如果将排名信息腌制到一个字段中,我必须通过编写自定义代码来管理任何结构更改。

If I change the fields in Rank, Django's migration facilities easily allow performing the needed changes when I deploy the new version of my application. If the rank information is pickled into a field, I have to manage any structure change by writing custom code.

数据库软件无法访问腌制中的值,并且因此您必须编写自定义代码才能访问它们。使用上述模型,如果您想按今天的排名列出学生(并且已经计算出今天的排名),则可以执行以下操作:

The database software cannot access values in a pickle and so you have to write custom code to access them. With the model above, if you want to list students by rank today (and the ranks for today have already been computed), then you can do:

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

如果使用泡菜,则必须扫描所有学生并解除等级,以提取所需日期的等级,然后使用Python数据结构按等级对学生进行排序。完成此操作后,您必须遍历此结构以按顺序获取名称。

If you use pickles, you have to scan all Students and unpickle the ranks to extract the one for the day you want, and then use a Python data structure to order the students by rank. Once this is done, you then have to iterate over this structure to get the names in order.

这篇关于如何在Django中记录模型的每日排名?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆