我正在为程序员提供招聘网站,每个用户都可以在线完成编程案例并查看结果。
这是我建立关系模型的方式(我省略了许多不重要的字段,只保留了有趣的字段):
这是我的候选人课程
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的唯一版本,以便我可以修改其状态,并且只影响一个候选人,而不是每个人。
感谢您的回答。
答案 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。手动进行操作以了解发生了什么(并能够将连接器用于其自己的字段)。