在 Django ORM 中,一个“学生-课程”模型设计
Posted
技术标签:
【中文标题】在 Django ORM 中,一个“学生-课程”模型设计【英文标题】:In Django ORM, A "Student - Course" Model design 【发布时间】:2012-06-16 16:11:12 【问题描述】:我想在 Django 中为一所在线私立学校设计一个模型。它侧重于Students
、Tutors
和Courses
之间的关系。
应该考虑的最重要的因素是Students
可以添加,Tutors
可以创建课程。
我想扩展内置 Djano 的“用户”并扩展其功能。
我设计了一个非常草稿的模型,如下所示:
from django.db import models
from django.contrib.auth.models import User , Group
from django.utils.translation import ugettext as _
class Course(models.Model):
name = models.CharField(max_length = 70)
slug = models.SlugField()
created = models.DateTimeField(auto_now = True)
updated = models.DateTimeField(auto_now_add = True)
description = models.TextField()
student = models.ManyToManyField('Student' , null = True, blank = True, related_name = _('Student courses'))
tutor = models.ManyToManyField('Tutor' , null = True, blank = True , related_name = _('Tutor courses'))
def __unicode__(self):
return self.name
class Meta:
verbose_name = ('course')
verbose_name_plural = ('courses')
class Student(models.Model):
user = models.ForeignKey(User , blank = True)
#photo = models.ImageField(_('photo'), upload_to='photos/', blank=True)
class Tutor(models.Model):
user = models.ForeignKey(User , blank = True)
#photo = models.ImageField(_('photo'), upload_to='photos/', blank=True)
首先:这是一个正确的方法吗?我想要用户,所以我可以在视图和模板层中使用它。
第二,如何查询哪个学生上过哪些课程?
先谢谢你..
【问题讨论】:
【参考方案1】:正如@cberner 所说,您应该查看用户配置文件。归根结底,您希望学生和导师都是真正的蓝色User
s,这样您就可以在他们登录后从请求中访问他们。
话虽如此,拥有单独的模型仍然有一些优点,只要它们是 代理 模型。您可以将代理模型视为一种别名。他们不能向数据库中添加额外的字段,但他们可以拥有自己独特的方法、管理器等。例如:
class Student(User):
class Meta:
proxy = True
def __unicode__(self):
return u'Student: %s' % super(Student, self).__unicode__()
这是一个非常基本的示例,但它旨在说明即使就数据库而言这仍然是 User
,您也可以覆盖和添加使其本身独一无二的方法。
当然,您需要一些方法来区分Student
和Tutor
,甚至是普通的旧User
。我发现群组是为User
代理完成此任务的最佳方式。例如,您可以创建“Student”和“Tutor”组,然后分配到“Student”组的任何用户,例如,都可以通过Student
模型获得。
class StudentManager(models.Manager):
def get_query_set(self):
return self.filter(groups__name='Student')
class Student(User):
class Meta:
proxy = True
def save(self, *args, **kwargs):
super(Student, self).save(*args, **kwargs)
if not self.groups.filter(name='Student').exists():
group, created = Group.objects.get_or_create('Student')
self.groups.add(group)
这样可以确保在您创建Student
时,它会自动添加到“学生”组中,如果您检索带有Student
的对象(例如Student.objects.all()
),您只会得到属于的User
s到“学生”组。
因为这些是单独的模型,您也可以在管理员中单独引用它们,因此您可以为Student
、Tutor
和常规User
提供单独的更改列表和更改表单,如果你想要的。
将它们分配给组还可以很容易地限制部分管理员。例如,由于只有Tutor
s 应该能够创建、更改或删除课程,您可以将以下方法添加到您的CourseAdmin
:
def has_add_permission(self, request):
return request.user.is_superuser or request.user.groups.filter(name='Tutor').exists()
def has_change_permission(self, request, obj=None):
return request.user.is_superuser or request.user.groups.filter(name='Tutor').exists()
def has_delete_permission(self, request, obj=None):
return request.user.is_superuser or request.user.groups.filter(name='Tutor').exists()
只有超级用户或“导师”组的成员才能添加全新课程或更改或删除现有课程。
【讨论】:
这是一个令人兴奋的回应.. 高五.. 但我仍然想知道是否要访问 Student's first_name ,我应该查询 "Student.course" 还是 "User.course" ?特别是,我应该通过ManyToManyField(直接或使用“通过”表)将课程链接到学生,对于导师也是如此。对吗?? 没关系。Student
只是User
的别名,因此无论您的实例是Student
还是User
,instance.course
都会为您提供所需的服务。 Course
应该是 M2M 关系(学生/导师有很多课程,课程有很多学生,也许还有导师)。但是,您的ManyToManyField
应该在Course
上,并且它应该指向User
。这包括学生和导师。
很好,但考虑到我们希望将学生与学校联系起来。我也应该为学生添加一些额外的字段。好吧,我还必须跟踪学生的活动!!所以我必须将学生链接到其他表格。使用代理模型拥有所有这些是否可行??
嗯.. 欺骗关系怎么样?比如说,我们有一个部门模型,其中包含“student = Models.ForeignKey(User,related_name='student')”字段??
当然。事实上,如果您最终需要多个外键到User
,无论如何您都必须给每个外键一个唯一的相关名称。另外,请记住,您仍然可以直接创建与代理模型的关系,即。 ForeignKey(Student)
。请注意,如果您这样做,则无法在该字段中存储通用 User
;它必须是真正的 Student
实例。【参考方案2】:
我会考虑使用 Django 支持的 user profiles 而不是 Student
和 Tutor
模型。此外,auth 模块有一个相当完整的permissions 模型,您可以使用它而不是创建自己的系统来只允许一些用户创建课程。
【讨论】:
感谢 cberner。你推荐这个而不是代理模型吗?除了普通的 Django User 字段之外,我还必须向 Student 和 Tutors 添加一些字段。以上是关于在 Django ORM 中,一个“学生-课程”模型设计的主要内容,如果未能解决你的问题,请参考以下文章
Python 3 & Django Rest Framework - 如何查询 M-1-M 模型?