Django上ManyToMany字段的唯一值

时间:2014-04-12 23:09:05

标签: django model many-to-many constraints unique

我需要一些非常简单的问题的帮助(简单解释,但不能为我解决)

我在Django中有以下模型:

class ClassGroup(models.Model):
    group = models.CharField(_('group'), max_length=3)
    course = models.ForeignKey(Course,
                               related_name='classgroups',
                               related_query_name='classgroup',
                               verbose_name=_('course'))
    students = models.ManyToManyField(Actor,
                                      related_name='student_classgroups',
                                      related_query_name='student_classgroup',
                                      verbose_name=_('student'))
    lecturers = models.ManyToManyField(Actor,
                                       related_name='lecturer_classgroups',
                                       related_query_name='lecturer_classgroup',
                                       verbose_name=_('lecturer'))

    class Meta:
        verbose_name = _('class group')
        verbose_name_plural = _('class groups')
        unique_together = ('group', 'course')

我需要添加一个约束,以防止Actor在每个ClassGroup中同时成为学生和讲师。是否可以在模型级别添加这样的约束?我想尽可能避免使用基于表单/视图的上层解决方案。

非常感谢你!

1 个答案:

答案 0 :(得分:1)

我认为没有办法在Django的数据库级别指定这个。您可以在模型的clean()validate_unique()方法中检查这一点,但这些方法仅在某些情况下调用。

一种方法是重构数据库,以便为学生和讲师使用单个表格,并使用role列区分它们。

class ClassGroup(models.Model):
    group = models.CharField(_('group'), max_length=3) 
    course = models.ForeignKey(Course, related_name='classgroups', 
                                       related_query_name='classgroup',
                                       verbose_name=_('course')) 
    actors = models.ManyToManyField(Actor, related_name='classgroups',
                                           through='ClassRole')


    class Meta: 
        verbose_name = _('class group') 
        verbose_name_plural = _('class groups') 
        unique_together = ('group', 'course')

class ClassRole(models.Model):
    class_group = models.ForeignKey(ClassGroup, related_name='roles')
    actor = models.ForeignKey(Actor, related_name='roles')

    STUDENT_ROLE = 10
    LECTURER_ROLE = 20
    ROLE_CHOICES = (
        (STUDENT_ROLE, _('student role')),
        (LECTURER_ROLE, _('lecturer role')),
    )
    role = models.PositiveSmallIntegerField(choices=ROLE_CHOICES)

在这种结构中,每个演员当然只有角色。您还可以编写自定义Managers和模型方法,以便轻松获得学生或讲师。