Reputation: 2746
I am working on a django application that contains a bunch of related objects. I have test objects, each with an ordered set of questions (each question has a correct_answer property). And I also have test attempt objects, which are related to test objects by a foreign key and each have their ordered set of question attempts each with a choice property. Essentially, each question attempt corresponds to a question (a test attempt only passes validation of it has the same number of question attempts as the test it is related to has questions), and then I can check the percentage right and wrong by outputting a values_list of correct_answers and choices and comparing the two lists. My model looks something like this:
ANSWERS = ((0,''),(1,'A'),(2,'B'),(3,'C'),(4,'D'),(5,'E'))
class Question(models.Model):
test = models.ForeignKey(Test,related_name='questions')
correct_answer = models.IntegerField(max_length=1,choices=ANSWERS)
def _get_score(self):
answers = self.test.test_attempts.values_list('answers_choice',flat=True)[self.test.get_question_order().index(self.pk)::self.test.questions.count()]
scores = [x==self.correct_answer for x in answers]
length = len(correct)
if length == 0:
return 0
return float(sum(scores))/length
score = property(_get_score)
class Meta:
order_with_respect_to = 'test'
class Test(models.Model):
testID = models.CharField(max_length=50,verbose_name='Test identification information')
def _get_score(self):
scores = [x.score for x in self.test_attempts.all()]
length = len(scores)
if length == 0:
return 0
return float(sum(scores))/length
score = property(_get_score)
class QuestionAttempt(models.Model):
test_attempt = models.ForeignKey(TestAttempt,related_name='answers')
choice = models.IntegerField(max_length=1,choices=ANSWERS)
def isCorrect(self):
return self.choice == Question.objects.get(pk=self.test_attempt.test.get_question_order()[self.test_attempt.get_questionattempt_order().index(self.pk)]).correct_answer
class Meta:
order_with_respect_to = 'test_attempt'
class TestAttempt(models.Model):
test = models.ForeignKey(Test,related_name='test_attempts')
student = models.ForeignKey(UserProfile,related_name='test_attempts')
def _get_score(self):
responses = self.answers.values_list('choice',flat=True)
correctAnswers = self.test.questions.values_list('correct_answer',flat=True)
s = [x==y for x,y in zip(responses,correctAnswers)]
length = len(s)
if length == 0:
return 0
return float(sum(s))/length
score = property(_get_score)
class Meta:
unique_together = ('student','test')
If you take a look at the QuestionAttempt Model and within that, the isCorrect method, you see how my predicament. It seems as if that is the only way to check obtain a per-question granularity to check if a given question attempt is right or wrong. My problem is that this one statement is literally 3 or 4 unique database queries (I can't even tell there are so many). I was thinking of using F statements, but I don't know the default name of the ordering column that django uses when specifying order_with_respect_to. Also, to get the score for a given question, I need to do 3+ db queries as well. Is there a better way to do this? How can I access the db entry for the order. I did some searching and theres a property called _order applied to both the question and the questionattempt model. Can I reliably use this? This would greatly simplify some of the code because I could query the database using a filter on the _order property as well
Upvotes: 0
Views: 1153
Reputation: 239400
The problem is with your logic in setting up the models. A QuestionAttempt
should be directly related to a Question
. Relying on the ordering to be the same is dubious at best, and most likely will fail at some point.
Upvotes: 1