假设我们有以下模型:
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
但是在“#注1”点,它每次都会运行一个查询,这会极大地降低性能(一个班级最多可容纳30名学生,每门课程多于50门课程)。
有更好的方法吗?也许还有更多的Django-ORM风格?
答案 0 :(得分:1)
是。请不要对每个表格单元格进行查询。这通常不是一个好主意。
我们可以先查询Course
和Student
,然后列出一个二维列表,例如:
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 个单元格是指courses
中第 i 个课程的等级和 j students
中的第3个学生。
然后我们可以像这样传递数据
return render(
request,
'some_template.html',
{'cols': students, 'rows': zip(students, table)}
)
,然后像这样渲染:
<table>
<thead>
<tr>
<th>×</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]来完成工作并删除样板代码。