Django:数据透视

时间:2014-04-08 18:52:56

标签: python sql django

我正在Django构建一个简单的学校注册应用程序,并且正在努力弄清楚如何创建报告。我认为这是数据的转移,但这可能不是我想要做的事情。广泛的研究和玩熊猫,图表等没有得到任何答案,所以我希望你能提供帮助。

class SemesterPeriod(models.Model):
    name = models.CharField(max_length=50)

class Schedule(models.Model):
    semester = text
    course = Foreign Key
    semester_period = models.ForeignKey(SemesterPeriod)

class Student(models.Model):
    first_name = models.CharField(max_length=50)

class StudentEnroll(models.Model):
    schedule = ForeignKey('Schedule')
    student = ForeignKey('Student')

两名学生的数据可能如此

SemesterPeriod
    1st_Period
    2nd_Period
    3rd_Period

Schedule
    Fall, Math, 1st_Period
    Fall, History, 2nd_Period
    Fall, Science, 3rd_Period

Student
    Chris
    Kim

StudentEnroll
    Math, Chris
    Science, Kim
    Science, Chris
    History, Kim

现在,我要展示的是这样的:

Student             1st_Period           2nd_Period          3rd_Period
Chris                Math                                      Science
Kim                                        History             Science

OR ......

Student             1st_Period           2nd_Period          3rd_Period
Chris                X                                          X
Kim                                        X                    X

我希望,我可以看到我如何转动"数据。由于我没有对其进行总结或汇总,因此我不知道这是否是正确的术语。无论如何,我无法弄清楚如何有效地做到这一点。我可以进行大量的数据库查询,但必须有一种更简单的方法。

1 个答案:

答案 0 :(得分:4)

您应该能够进行两次数据库查询,(1)您获得所有学生注册(使用适当的其他数据获取),以及(2)您获得所有期间的排序列表。您可能可以远离优化第二个查询(但我个人并不打扰)。

在您的视图中使用defaultdict处理此StudentEnroll列表:

from collections import defaultdict

enrolls = StudentEnroll.objects.filter(semester=semester).values_list(
            'student__name', 'schedule__course', 'schedule__semester_period__name')
# Fetch all the enrolled data; this puts them in a list of tuples like 
# [("Chris", "Math", "1st_Period"), ("Kim", "Science", "3rd_Period"), ... ]

periods = SemesterPeriod.objects.values_list('name', flat=True).order_by('name')
# get names of all periods in a flat list like: ['1st_Period', '2nd_Period', '3rd_Period'] 

period_dict = dict([(period,i) for i,period in enumerate(periods)])
# enumerate(periods) is a generator that has data in the form 
# [(0, '1st_Period'), (1, '2nd_Period'), (2, '3rd_Period')] -- it enumerates the list.
# I then use a list comprehension to reverse it:
# [(period,i) for i,period in enumerate(periods)] is
# [('1st_Period', 0), ('2nd_Period', 1), ...]
# and then convert that list of paired tuples into a dictionary:
# {'1st_Period': 0, '2nd_Period': 1, '3rd_Period': 2}
# period_dict['3rd_Period'] returns 2; indicating that classes that are third period
# should fall into a students schedule in the third slot of the list 
# (first element of list is 0)

students_dict = defaultdict(lambda: [""]*len(periods))
# a defaultdict that when a new student (not previously stored) is seen
# initializes that student to have an empty schedule.
# the empty schedule is an empty list that is as long as the number of periods,
# with each period an empty string ''
# student_dict once fully populated will be of form
# {'Chris': ['Math', '', 'Science'], 'Kim': ['', 'History', 'Science']}
# Note student_dict['Chris'] = ['Math', '', 'Science'] and 
# student_dict['Chris'][0] = 'Math'.
for (student_name, course, period) in enrolls:
    students_dict[student_name][period_dict[period]] = course
    # go through the list of enrolls and assign courses to the schedule in the appropriate spots.

student_list = list(student_dict.items())    
# [['Chris', ['Math', '', 'Science']], ['Kim', ['', 'History', 'Science']],]

然后通过上下文变量将student_list和句点返回到模板,并使用类似

的内容
<table>
<thead>
  <tr> 
    <th>Student</th>
  {% for per in periods %}
    <th>{{ per }}</th>
  {% endfor %}
  </tr>
</thead>
<tbody>
  {% for student_row in student_list %}
     <tr><th>{{ student_row.0 }}</th>
     {% for class in student_row.1 %}
        <td>{{ class }}</td>
     {% endfor %}
     </tr>
  {% endfor %}
</tbody>
</table>