J. Hesters
J. Hesters

Reputation: 14824

Django unique together constrain with relations

I'm writing a REST API using Django and Django Rest Framework. I'm currently writing the models.

I have a model for students, a model for questions and a model for answers.

class Question(models.Model):
    question_text = models.CharField()


class Answer(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    answer_text = models.CharField()


class Student(models.Model):
    name = models.CharField()

The students should be able to pick one and only one answer per question. So I was thinking of designing a student picked answer model - so that I can let the students pick through a relation - like this:

class StudentPickedAnswer(models.Model):
    student = models.ForeignKey(Student, on_delete=models.CASCADE)
    answer = models.ForeignKey(Answer, on_delete=models.CASCADE)

I found that there is a unique_together constraint for the class Meta. But it seems to me that it can't specify relations. I would need something like this;

class Meta:
   unique_together = ('student', 'answer__question')

How can I achieve that the students can only pick one question per answer? Or is picking through a model with relations a bad design?

Upvotes: 3

Views: 417

Answers (1)

Angela
Angela

Reputation: 1731

Because you mentioned that students need to pick answers for questions, I think you need to have a model for your question options/choices. You can then model your studentresponse model with the uniquetogether on the (student, question)

class Question(models.Model):
    question_text = models.CharField()
    options = models.ManyToManyField(QuestionOption)

class QuestionOption(models.Model):
    option_text = models.CharField(max_length=255)

class Student(models.Model):
    name = models.CharField()

class StudentResponse(models.Model):
    student = models.ForeignKey(Student)
    question = models.ForeignKey(Question)
    response_option = models.ForeignKey(QuestionOption)

    class Meta:
        unique_together = ("student", "question")

Another approach if every question needs to have unique choices. This is similar to the polls app tutorial in the Django documentation.

class Question(models.Model):
    question = models.CharField(...)

class QuestionOption(models.Model):
    question = models.ForeignKey("Question",related_name="qs_options")
    option = models.CharField(max_length=200)

    class Meta:
       # ensuring choices are not duplicated for a question.
       unique_together = ("question", "option")

Upvotes: 1

Related Questions