Django如何使ManyToMany字段的每个成员唯一?

时间:2018-10-26 10:05:18

标签: django django-models django-views

我正在为程序员提供招聘网站,每个用户都可以在线完成编程案例并查看结果。

这是我建立关系模型的方式(我省略了许多不重要的字段,只保留了有趣的字段):

这是我的候选人课程

class Candidate(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
cases = models.ManyToManyField(Case)

这是我的Case课

class Case(models.Model):
title = models.CharField(verbose_name="Titre", max_length=1000)
test1_complete = models.BooleanField(verbose_name="Test 1 Complété", default=False)
test2_complete = models.BooleanField(verbose_name="Test 2 Complété", default=False)
test3_complete = models.BooleanField(verbose_name="Test 3 Complété", default=False)
test4_complete = models.BooleanField(verbose_name="Test 4 Complété", default=False)

然后,我在用户面板上创建了两个候选对象和一个案例,并通过ManyToMany字段将两个用户与该案例相关联。 测试完成布尔值字段是指用户是否完成了当前案例的每组​​测试。

这是我如何在视图中获取每个用户的Case的信息:

def fetch_cases_info(request):
first_case = Candidate.objects.filter(user=request.user).values_list("cases", flat=True) 
user_case = Case.objects.get(id=first_case)

我的问题是每个候选人都有相同的Case对象,因此如果User1完成案例的test1,则每个User会将其设置为true。

我的目标是,当我对存储在候选对象的ManyToMany字段中的Case进行更改时,它只会为此更改,而不会为使用此Case的每个人进行更改。

有人对如何建立这种关系有任何想法吗? 我希望每个候选人都可以拥有多个Case,但是它们应该是Case的唯一版本,以便我可以修改其状态,并且只影响一个候选人,而不是每个人。

感谢您的回答。

2 个答案:

答案 0 :(得分:1)

您可以使用ManyToManyField的through参数,但是我建议稍微更改一下模式。我在这里做一个假设,但是为每个测试增加一个新的列可能不是最好的主意(请考虑一下,如果将来您的案例可以包含更少或更多的测试)

class Case(models.Model):
    title = models.CharField(verbose_name="Titre", max_length=1000)

class TestCase(models.Model):
    case = models.ForeignKey(Case)
    number = models.PositiveIntegerField()

class Candidate(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
    completed_tests = models.ManyToManyField(TestCase)

然后找出给定案例解决了哪些测试,请

candidate.completed_tests.filter(case=mycase)

答案 1 :(得分:0)

除非另有说明,否则

ManyToManyField将创建第三个表以用作连接器。这是关系数据库知道如何建立多对多关系的唯一方法。 complete布尔字段属于此联接器表,而不属于两个多对多表中的任何一个。

因此,相反地,请执行Django的操作,但要手动进行:为(例如)锻炼创建模型;说每个候选人可以有很多练习,但是每个练习都属于一个候选人;每个案例都在许多练习中完成,但是每个练习都是一个案例。然后将您的布尔值放在“运动”表上。然后,您可以根据需要在through='Exercise'上粘贴ManyToManyField,这样您就可以方便地访问candidate.cases,反之亦然,因为您知道它的实际作用。

tl; dr:ManyToManyField是一个hack。手动进行操作以了解发生了什么(并能够将连接器用于其自己的字段)。