Django上ManyToMany字段的唯一值

Posted

技术标签:

【中文标题】Django上ManyToMany字段的唯一值【英文标题】:Unique values across ManyToMany fields on Django 【发布时间】:2014-05-27 01:31:06 【问题描述】:

我需要一些帮助来解决一个非常简单的问题(解释起来很简单,但不是为我解决)

我在 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】:

我认为没有任何方法可以在 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 和模型方法,以便轻松获取学生或讲师。

【讨论】:

非常感谢您的快速回答。你的解决方案无疑是非常好的,但是我和我的团队在我们的项目中处于先进的状态,所以我们希望避免模型更改,因为我们需要重构很多东西。但是,我们会检查是否有可能继续您的想法。如果不是,那么我认为我们将定义一个 clean() 方法(这实际上很糟糕,但我们没有更好的主意)。

以上是关于Django上ManyToMany字段的唯一值的主要内容,如果未能解决你的问题,请参考以下文章

如何使 ManyToMany 字段的值显示在 Django 通用 DeleteView 中

Django ManyToMany 字段的 set() 操作是不是清除现有关系?

如何更新Django 的ManyToMany 字段

使用 Django admin 时未保存 ManyToMany 字段

Django ManyToMany 字段上的自定义列名

如何在模板上显示 Django ManyToMany?需要简单的代码