【问题标题】:DRF serializer to group data by attributes into arraysDRF 序列化器按属性将数据分组到数组中
【发布时间】:2020-01-22 22:11:57
【问题描述】:

我想创建一个 Django Rest Framework 序列化程序,它可以根据每个对象的属性对我的数据进行分组。

我的模型描述如下:

class Courses(models.Model):
    coursenum = models.AutoField(db_column='courseNum', primary_key=True)
    coursecode = models.CharField(db_column='courseCode', max_length=10, blank=True, null=False)

    class Meta:
        managed = False
        db_table = 'courses'


class Sections(models.Model):
    sectionnum = models.AutoField(db_column='sectionNum', primary_key=True)
    semester = models.CharField(max_length=1, blank=True, null=False)
    section = models.CharField(max_length=2, blank=True, null=False)

    class Meta:
        managed = False
        db_table = 'sections'

class Teachers(models.Model):
    teachernum = models.AutoField(db_column='teacherNum', primary_key=True)
    teachername = models.CharField(max_length=60, blank=True, null=False)

    class Meta:
        managed = False
        db_table = 'teachers'


class Timeslots(models.Model):
    timeslotnum = models.AutoField(db_column='timeSlotNum', primary_key=True)
    starttime = models.TimeField(db_column='startTime', blank=True, null=False)
    endtime = models.TimeField(db_column='endTime', blank=True, null=False)

    class Meta:
        managed = False
        db_table = 'timeslots'


class Venues(models.Model):
    venuenum = models.AutoField(db_column='venueNum', primary_key=True)
    venuename = models.CharField(db_column='venueName', max_length=6, blank=False, null=False)

    class Meta:
        managed = False
        db_table = 'venues'


class Slots(models.Model):
    daynum = models.IntegerField(db_column='dayNum', primary_key=True)
    venuenum = models.ForeignKey(Venues, models.CASCADE, db_column='venueNum')
    timeslot = models.ForeignKey(Timeslots, models.CASCADE, db_column='timeSlot')
    coursenum = models.ForeignKey(Courses, models.CASCADE, db_column='courseNum', blank=True, null=True)
    teachernum = models.ForeignKey(Teachers, models.CASCADE, db_column='teacherNum', blank=True, null=True)
    sectionnum = models.ForeignKey(Sections, models.CASCADE, db_column='sectionNum', blank=True, null=True)

    class Meta:
        managed = False
        db_table = 'slots'
        unique_together = (('daynum', 'venuenum', 'timeslot'),)

使用带有嵌套兄弟序列化器调用的简单模型序列化器,我可以获得如下数据:

"slots": [
        {
            "daynum": 1,
            "venue": {
                "venuenum": 2,
                "venuename": "FF-105"
            },
            "timeslot": {
                "timeslotnum": 2,
                "starttime": "09:30:00",
                "endtime": "10:20:00"
            },
            "course": null,
            "teacher": null,
            "section": null
        },
        {
            "daynum": 1,
            "venue": {
                "venuenum": 2,
                "venuename": "FF-105"
            },
            "timeslot": {
                "timeslotnum": 3,
                "starttime": "10:30:00",
                "endtime": "11:20:00"
            },
            "course": {
                "coursenum": 1,
                "coursecode": "CS 2002"
            },
            "teacher": {
                "teachernum": 1,
                "teachername": "TEHNIAT MIRZA"
            },
            "section": {
                "sectionnum": 1,
                "semester": "3",
                "section": "B"
            }
        },
]

但是,我想在 React 表中迭代这些结果,并希望根据每个对象的属性对它们进行排序和分组,以便于显示:

期望的输出

"slots": [
    '1': //the day number
        [
            'FF-104': []
            'FF-105': [
                    {
                        "daynum": 1,
                        "venue": {
                            "venuenum": 2,
                            "venuename": "FF-105"
                        },
                        "timeslot": {
                            "timeslotnum": 2,
                            "starttime": "09:30:00",
                            "endtime": "10:20:00"
                        },
                        "course": null,
                        "teacher": null,
                        "section": null
                    },
                    {
                        "daynum": 1,
                        "venue": {
                            "venuenum": 2,
                            "venuename": "FF-105"
                        },
                        "timeslot": {
                            "timeslotnum": 3,
                            "starttime": "10:30:00",
                            "endtime": "11:20:00"
                        },
                        "course": {
                            "coursenum": 1,
                            "coursecode": "CS 2002"
                        },
                        "teacher": {
                            "teachernum": 1,
                            "teachername": "TEHNIAT MIRZA"
                        },
                        "section": {
                            "sectionnum": 1,
                            "semester": "3",
                            "section": "B"
                        }
                    },
            ]
        ]
]1

总而言之,我想做的是
在第一级,按 daynum 属性对结果进行分组
在第二层,按场地名称(或任何有效的数字)对结果进行分组,同时按时间段排序。

【问题讨论】:

  • 序列化器没有真正的逻辑,所以你不能这样做。您最多需要对数据库进行自定义查询,或者在 python 代码中滚动您自己的查询。你也可以在 React 中做 :) 你有没有考虑过用 python 标准命名你的模型,然后使用 github.com/vbabiy/djangorestframework-camel-case 转换为 camelCase?
  • @AndrewBacker 非常感谢!我写了一个自定义查询,答案如下

标签: python json django django-rest-framework serialization


【解决方案1】:

因此,根据我的发现,Django Rest Framework 序列化程序不能以这种方式工作,正如@Andrew Backer 指出的那样,我可能必须使用自定义查询来相应地检索数据。

我最初研究了itertools.groupby,但它对我来说不是那么直观,所以我决定编写一个自定义查询。

查询的工作原理:

  • 检索所有 Slot 对象,但按如下顺序排列它们: Slots.objects.all().order_by('daynum','venuenum__venuename','timeslot')

  • 使用嵌套的collections.defaultdict,即: data = defaultdict(lambda: defaultdict(list))
  • 对于每个daynum,为venuenum__venuename 添加一个列表并相应地附加插槽对象

    代码:

    class TimetableGenerateView(APIView):
        def get(self, request):
            data = defaultdict(lambda: defaultdict(list))
            slots = Slots.objects.all().order_by('daynum','venuenum__venuename','timeslot')
            for slot in slots:
                data[slot.daynum][slot.venuenum.venuename].append(SlotSerializer(slot).data)
            return Response(data)
    
  • 【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-29
      • 1970-01-01
      • 1970-01-01
      • 2012-09-07
      • 2020-11-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多