尝试创建一种有效的方法来产生具有组合结果的交叉连接

Posted

技术标签:

【中文标题】尝试创建一种有效的方法来产生具有组合结果的交叉连接【英文标题】:Trying to create an efficient way to produce a cross join with combined results 【发布时间】:2019-11-28 09:54:18 【问题描述】:

假设我们有这些模型:

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

class Student(models.Model):
      name = models.CharField(max_length=255)
      clas-s-room = 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 风格?

【问题讨论】:

【参考方案1】:

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

我们可以先查询Courses和Students,然后做一个二维列表,比如:

courses = Course.objects.all()
students = Student.objects.filter(clas-s-room=clas-s-room)

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__clas-s-room=clas-s-room):
    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的学生。

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

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] 来完成这项工作并删除样板代码。

【讨论】:

在过去的 30 分钟里,我一直试图让它工作,但我似乎无法弄清楚。我得到了一张人满为患的桌子,这很棒,就像我已经非常感谢你一样!但是,当试图在模板中显示表格时遇到问题,当表格中只有 id 时,我将如何打印课程/学生姓名?您通常不能从 pk 返回对象,对吗?是否正在编写一个函数来获取您推荐的对象? @MrDikke:这应该类似于更新答案中的模板。 是的,我想我不会教那个!非常感谢!

以上是关于尝试创建一种有效的方法来产生具有组合结果的交叉连接的主要内容,如果未能解决你的问题,请参考以下文章

我想了解为啥要创建一种类型来处理 Go 中的错误以及您如何决定它应该具有啥基础类型

向 Card 添加一个方法,该方法创建一副完整的纸牌,每个等级和花色组合一张牌

交叉连接两个向量的元素以产生第三个向量

Flutter 浮动操作按钮错误!尝试创建一排具有响应式触摸效果的按钮

从零开始用golang创建一条简单的区块链

使用扩展语法创建一系列自然数