PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Làm cách nào để ghi lại thứ hạng hàng ngày cho một người mẫu trong Django?

Tôi sẽ đề xuất điều gì đó tương tự như những gì e4c5 đề xuất , nhưng tôi cũng sẽ:

  • Tạo chỉ mục vào ngày xếp hạng để tối ưu hóa việc đạt được tất cả các thứ hạng vào bất kỳ ngày nào.

  • Đánh dấu ngày tháng và sinh viên là unique_together . Điều này ngăn khả năng ghi lại hai cấp bậc cho cùng một học sinh vào cùng một ngày.

Các mô hình sẽ giống như sau:

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

Trong một ứng dụng chính thức, tôi cũng mong đợi có một số ràng buộc về tính duy nhất đối với GradeStudent nhưng vấn đề được trình bày trong câu hỏi không cung cấp đủ chi tiết về các mô hình này.

Sau đó, bạn có thể chạy một công việc hàng ngày với cron hoặc bất kỳ trình quản lý tác vụ nào bạn muốn sử dụng (Cần tây cũng là một tùy chọn), để chạy một lệnh như sau sẽ cập nhật các cấp bậc theo một số tính toán và xóa các bản ghi cũ. Đoạn mã sau là một minh họa về cách nó có thể được thực hiện. Mã thực phải được thiết kế để nói chung là không có giá trị (mã sau đây không phải là do việc tính toán thứ hạng là ngẫu nhiên) để nếu máy chủ được khởi động lại ở giữa bản cập nhật, lệnh có thể được chạy lại. Đây là mã:

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

Tại sao không phải là dưa chua?

Nhiều lý do:

  1. Đó là một sự tối ưu hóa quá sớm, và về tổng thể có lẽ không phải là một sự tối ưu hóa nào cả. Một số các hoạt động có thể nhanh hơn, nhưng các hoạt động khác sẽ chậm hơn. Nếu xếp hạng được chọn vào một trường trên Student sau đó, tải một học sinh cụ thể vào bộ nhớ có nghĩa là tải tất cả thông tin xếp hạng vào bộ nhớ cùng với học sinh đó. Điều này có thể được giảm thiểu bằng cách sử dụng .values() hoặc .values_list() nhưng sau đó bạn không còn nhận được Student phiên bản từ cơ sở dữ liệu. Tại sao có Student ngay từ đầu và không chỉ truy cập vào cơ sở dữ liệu thô?

  2. Nếu tôi thay đổi các trường trong Rank , Các cơ sở di chuyển của Django dễ dàng cho phép thực hiện các thay đổi cần thiết khi tôi triển khai phiên bản mới của ứng dụng của mình. Nếu thông tin xếp hạng được chọn vào một trường, tôi phải quản lý mọi thay đổi cấu trúc bằng cách viết mã tùy chỉnh.

  3. Phần mềm cơ sở dữ liệu không thể truy cập các giá trị trong một hộp và vì vậy bạn phải viết mã tùy chỉnh để truy cập chúng. Với mô hình trên, nếu bạn muốn liệt kê các sinh viên theo thứ hạng ngày hôm nay (và thứ hạng cho ngày hôm nay đã được tính toán), thì bạn có thể thực hiện:

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

    Nếu bạn sử dụng dưa chua, bạn phải quét tất cả Students và bỏ chọn các thứ hạng để trích xuất thứ hạng cho ngày bạn muốn, sau đó sử dụng cấu trúc dữ liệu Python để sắp xếp các sinh viên theo thứ hạng. Sau khi hoàn tất, bạn phải lặp lại cấu trúc này để sắp xếp các tên.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Sử dụng UUID với EclipseLink và PostgreSQL

  2. Làm cách nào để cung cấp cho Npgsql một kiểu dữ liệu tùy chỉnh làm tham số?

  3. LISTAGG (cơ sở dữ liệu Oracle) trong PostgreSQL là gì?

  4. org.postgresql.util.PSQLException:LỖI:không thể tuần tự hóa quyền truy cập do phụ thuộc đọc / ghi giữa các giao dịch

  5. Kiến thức cơ bản về kích hoạt PostgreSQL và hàm được lưu trữ