【发布时间】:2020-07-28 19:22:02
【问题描述】:
我有这些模型:
组织
学生
课程
注册
学生属于组织
学生可以注册一门或多门课程
因此,注册记录基本上由给定的课程和给定的学生组成
from django.db import models
from model_utils.models import TimeStampedModel
class Organisation(TimeStampedModel):
objects = models.Manager()
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Student(TimeStampedModel):
objects = models.Manager()
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(unique=True)
organisation = models.ForeignKey(to=Organisation, on_delete=models.SET_NULL, default=None, null=True)
def __str__(self):
return self.email
class Course(TimeStampedModel):
objects = models.Manager()
language = models.CharField(max_length=30)
level = models.CharField(max_length=2)
def __str__(self):
return self.language + ' ' + self.level
class Meta:
unique_together = ("language", "level")
class EnrollmentManager(models.Manager):
def org_students_enrolled(self, organisation):
return self.filter(student__organisation__name=organisation).all()
class Enrollment(TimeStampedModel):
objects = EnrollmentManager()
course = models.ForeignKey(to=Course, on_delete=models.CASCADE, default=None, null=False, related_name='enrollments')
student = models.ForeignKey(to=Student, on_delete=models.CASCADE, default=None, null=False, related_name='enrollments')
enrolled = models.DateTimeField()
last_booking = models.DateTimeField()
credits_total = models.SmallIntegerField(default=10)
credits_balance = models.DecimalField(max_digits=5, decimal_places=2)
请注意自定义 EnrollmentManager,它允许我查找从给定组织注册的所有学生。
如何添加自定义管理器以检索学生注册的给定组织的所有课程?
我的尝试
我想创建一个 CourseManager 并以某种方式从关系的那一侧查询/过滤:
class CourseManager(models.Manager):
def org_courses_enrolled(self, organisation):
return self.filter(enrollment__student__organisation__name=organisation).all()
这可行,但它给了我相同的 100 条注册记录 :(
我想要得到的是: 基于给定的组织 查找所有已注册的学生 然后 (DISTINCT?) 获取该组织的已注册课程列表
这是风景:
class OrganisationCoursesView(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
serializer_class = CourseSerializer
queryset = Course.objects.get_courses(1)
和网址:
# The below should allow: /api/v1/organisations/1/courses/
router.register('api/v1/organisations/(?P<organisation_pk>\d+)/courses', OrganisationCoursesView, 'organisation courses')
更新 1
根据 h1dd3n 的回答,我接下来尝试了这个:
class CourseManager(models.Manager):
def get_queryset(self):
return super(CourseManager, self).get_queryset()
def get_courses(self, organisation):
return self.get_queryset().filter(student__organisation_id=organisation)
但这会引发错误(正如我所料):
FieldError:无法将关键字“学生”解析为字段。选择是: 课程、创建、id、语言、级别、修改、进度
更新 2 - 越来越近了!
好的,在 @AKX 的 cmets 的帮助下:
class CourseManager(models.Manager):
def get_queryset(self):
return super(CourseManager, self).get_queryset()
def get_courses(self, organisation):
return self.get_queryset().filter(courses__student__organisation_id=organisation)
现在确实会返回课程,但它会为每个注册学生返回一份副本。所以现在我需要对它们进行分组,这样每条记录只会出现一次......
【问题讨论】:
-
顺便说一句,由于
Organisation.name不是唯一的,如果有多个同名组织,使用organisation__name可能会返回意外结果。 -
好地方,谢谢,我已经改用 id 了
-
filter(enrollment_set__student__organisation_id=organisation)是否有用? -
否 - 无法解析关键字 'enrollment_set' :( 请注意,课程的外键是在 Enrollment 中定义的(学生外键也是如此)
标签: python django django-rest-framework django-queryset