1

假设我们有这些模型:

class ClassRoom(models.Model):
      name = models.CharField(max_length=255)

class Student(models.Model):
      name = models.CharField(max_length=255)
      classroom = models.ForeignKey(ClassRoom......

class Course(models.Model):
      name = models.CharField(max_length=255)

class Grades(models.Model):
      student = models.ForeignKey(Student....
      course = models.ForeignKey(Course....
      grade = models.CharField(.....

我想创建课程和学生的交叉连接,但成绩在表中。

|          | Student A | Student B |
| Course 1 | 8         |           |
| Course 2 | 6         | 4         |

请注意,学生 B 尚未获得课程 1 的成绩!

我目前像这样解决这个问题

query = list(product(courses, students)
grades = Grades.objects.all.....
for i, query_tuple in enumerate(query):
     grade = grades.filter(query_tuple[0], query_tuple[1]
     if grade: # Note 1
         # Here I add it to a list of the grades

但是在“# Note 1”处,它每次都会运行一个查询,这会大大降低性能(一个班级最多可以有 30 名学生,每门课程超过 50 门)。

有一个更好的方法吗?也许更多的是 Django-ORM 风格?

4

1 回答 1

1

的。请不要对每个表格单元格进行查询。这通常不是一个好主意。

我们可以先查询Courses 和Students,然后制作一个 2d 列表,例如:

courses = Course.objects.all()
students = Student.objects.filter(classroom=classroom)

coursemap = { c.pk: i for i, c in enumerate(courses) }
studentmap = { s.pk: i for i, s in enumerate(students)}

table = [[None] * len(student) for __ in range(len(courses))]

for grade in Grade.objects.filter(student__classroom=classroom):
    row = coursemap.get(grade.course_id)
    col = coursemap.get(grade.student_id)
    if row is not None and col is not None:
        table[row][col] = grade.grade

所以最后table是一个成绩列表,None如果不存在成绩。表格中的第i,j个单元格是指第i个课程的成绩courses和第j个学生的成绩students

然后我们可以像这样传递数据:

return render(
    request,
    'some_template.html',
    {'cols': students, 'rows': zip(students, table)}
)

然后像这样渲染:

<table>
    <thead>
        <tr>
            <th>&times;</th>
            {% for student in cols %}
                <th>{{ student.name }}</th>
            {% endfor %}
        </tr>
    </thead>
    <tbody>
        {% for course, grades in rows %}
            <tr>
                <th>{{ course.name }}</th>
                {% for grade in grades %}
                    <td>{{ grade|default_if_none:'' }}</td>
                {% endfor %}
            </tr>
        {% endfor %}
    </tbody>
</table>

但是,您可以使用django-pivot[PiPy]来完成这项工作并删除样板代码。

于 2019-07-19T11:54:00.313 回答