我有一个包含这些模型的网站:
class TrainingSession(models.Model):
user = models.ForeignKey(user)
active_exercise = models.ForeignKey(Exercise)
class Passage(models.Model):
text = models.TextField()
class Exercise(models.Model):
training_session = models.ForeignKey(TrainingSession)
passage = models.ForeignKey(Passage)
为用户分配了TrainingSession
,用于生成段落练习。
网站的一般想法是让用户阅读练习。但是我希望通过用户在当前会话期间尚未阅读的段落生成新的练习。所以为此,TrainingSession
类有这个方法:
# this passes
def generate_exercise(self):
passages = Passage.objects.exclude(exercise__trainingsession=self)
if not passages:
raise ObjectDoesNotExist()
passage = random.choice(passages)
new_exercise = Exercise.objects.create(training_session=self,
passage=passage)
self.active_exercise = new_exercise
因此,如果我在创建任何段落之前尝试生成练习,那么您需要提出ObjectDoesNotExist
。而这正是本次测试中发生的事情:
# this test passes
def test_no_passages(self):
Passage.objects.all().delete()
user = User.objects.create()
session = TrainingSession.objects.create(user=user)
with self.assertRaises(ObjectDoesNotExist):
session.generate_exercise()
如果我有一个段落,并产生练习,它就有效:
# this test passes
def test_generate_one(self):
Passage.objects.all().delete()
user = User.objects.create()
session = TrainingSession.objects.create(user=user)
Passage.objects.create(passage_title='a', passage_text='b')
session.generate_exercise()
如果我有一个段落,并尝试连续生成两个练习,它会引发异常,正如我所希望的那样:
# this test passes
def test_cant_generate_second(self):
Passage.objects.all().delete()
user = User.objects.create()
session = TrainingSession.objects.create(user=user)
Passage.objects.create(passage_title='a', passage_text='b')
session.generate_exercise()
with self.assertRaises(ObjectDoesNotExist):
session.generate_exercise()
但是如果我有两个段落,并尝试生成三个练习,则不会引发错误,并且此后续测试失败:
# never raises the exception and fails
def test_cant_generate_third(self):
Passage.objects.all().delete()
user = User.objects.create()
session = TrainingSession.objects.create(user=user)
Passage.objects.create(passage_title='a', passage_text='b')
Passage.objects.create(passage_title='c', passage_text='d')
session.generate_exercise()
session.generate_exercise()
with self.assertRaises(ObjectDoesNotExist):
session.generate_exercise()
如果我打印出应该使用的'通道:
print 'used:', [ex.passage for ex in
Exercise.objects.filter(trainingsession=session)]
在最后一次测试中的不同点,发生了一些奇怪的事情。当我还没有产生任何练习时,它一开始是空的。在我生成第一个练习之后,它打印出一个数组,其中第一个生成的练习附加了这个练习。但是当我进行第二次练习时,它只能显示最新的练习和通行证。所以不知何故,
Exercise.objects.filter(trainingsession=session)
只找到最新创建的练习,而不是我创建的指向指定训练课程的所有练习。
所以我的问题是:可能有这样一条原因:
new_exercise = Exercise.objects.create(training_session=self,
passage=passage)
可能导致以后的查询:
passages = Passage.objects.exclude(exercise__trainingsession=self)
是不是行为不端?
我已经尝试过:
new_exercise.save() # --doesn't help
或者,如果这个问题没有明显的答案,我的跟进:你能看出我做错了吗?
答案 0 :(得分:0)
想出来:
passages = Passage.objects.exclude(exercise__trainingsession=self)
应该是
passages = Passage.objects.exclude(exercise__training_session=self)
使用
exercise__trainingsession
正在遵循TrainingSession到ExerciseSession的active_exercise外键的反向路径,因此只排除了“主动”练习。