how to make primay or unique three field in django models? - django

I have the four models in my Django models.py ( User, Exam, Questions, Answers )
the Answer model has four fields ( user, exam, question, answer)
after creating an exam and creating questions for that, the users come to take an exam
I want to store the user's answers in the Answer model, therefore, I specify which user is taking which exam and answering which question, at the end I save the user's answers in the last field ( the 'answer' field in Answer modle )
but I want this user only once can answer this question in this exam, so I want to make these fields ( user, exam, question ) primary in the Answer model that
my Answer model:
class Answer(models.Model):
exam = models.ForeignKey(Exam, on_delete=models.CASCADE, default=None)
user = models.ForeignKey(User, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.CharField(max_length=8)
I don't know how to do this action to primary three field
actually, there is no matter whether the two or one fields of these three fields are similar, I just want to prevent storing records that user, exam, and question fields are already stored
for example, I have this record in my database:
user:1, exam:52, question:38, answer: "option_a"
when I want to store the following record I expect to get an error:
user:1, exam:52, question:38, answer:"option_b"
but this record is ok:
user:1, exam:52, question:60, answer:"option_c"

Django want only one field as primary key.
The solution in your case is to use unique_together for your three fields:
class Answer(models.Model):
exam = models.ForeignKey(Exam, on_delete=models.CASCADE, default=None)
user = models.ForeignKey(User, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.CharField(max_length=8)
class Meta:
unique_together = ['user', 'exam', 'question']
Documentation about unique_together option: https://docs.djangoproject.com/fr/4.1/ref/models/options/#unique-together

Related

How to apply condition in boolean field in django rest framework?

I am working on a blog type website.
where students will ask question and teacher will answer it.
I put two user role
Teacher and student
class User(AbstractBaseUser, PermissionsMixin):
USER_TYPE = (
('None', 'None'),
('Student', 'Student'),
('Teacher', 'Teacher'),
)
user_type = models.CharField(choices=USER_TYPE, default='Student', max_length=50)
This is the user model where the role is defined.
Post model for submitting the question and Comment model for answering it.
In the Post model I put on field is_answered and as default put it False
class add_question(models.Model):
created_by = models.ForeignKey(User, blank=False, on_delete=models.CASCADE)
is_answered = models.BooleanField(default=False)
And the answer model [which is comment one] is referred to as the foreign key of the question
class submit_answer(models.Model):
question_id = models.ForeignKey(
add_question, blank=False, on_delete=models.CASCADE)
created_by = models.ForeignKey(User, blank=False, on_delete=models.CASCADE)
Both question and answer model contains created_by field and ForeignKey of User and answer model contains another ForeignKey of question.
so I need when the teacher role will put a comment the is_answered Field in add_question model should turn as true.
as student also can comment on his/er question so I need on condition to apply.
I am using serializer as I need API of this
So, should I modify on my views.py or serializers.py and how should I do that!
It would be great help if someone guide me how to do it?
Thanks and let me know if any other information needed.
The best practice would be adding such codition in save() method of models.Model. You should name your Model classes differently, like Question and Answer, because after creating, if you want to edit or something, it would be weird if you have to search for submit_answer, right? And as #wjh18 said, use CamelCase in classes.
Also question_id is usually bad idea, better think of question, because it will lead directly to the whole object, not its id.
class Answer(models.Model):
question = models.ForeignKey(Question, blank=False, on_delete=models.CASCADE)
created_by = models.ForeignKey(User, blank=False, on_delete=models.CASCADE)
def save(self, *args, **kwargs):
if self.created_by.user_type == 'Teacher' and not self.question.is_answered:
self.question.is_answered = True
self.question.save()
super().save(*args, **kwargs)

Ordering by a field in reverse side foreign key in Django

I have the following models
class Question(models.Model):
content=models.TextField()
...
class Answer(models.Model):
created_at = models.DatetimeField(auto_add=True)
author = models.ForeignKey(User, ... )
content = models.TextField()
question = models.ForeignKey(Question, ....)
...
class meta:
unique_together=('author','question')
in the database I have a set of questions and answers. answers are linked to their authors.
unique_together ensures the user can give an answer only once to a question.
usr_1 Is a user instance that has answers to some questions that I can retrieve by:
qst_qs=Question.objects.filter(answer__author=usr_1)
I want to sort questions in qst_qs according to the created_at field in usr_1's answer in each question.
Thanks in advance.
Please try this code:
qst_qs=Question.objects.filter(answer__author=usr_1).order_by('answer__created_at')

Django Prefetch not fetching the related fields

I have four models that reference a CustomUser table.
class Profile(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
...
class Question(models.Model):
question = models.CharField(max_length=140)
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='answers')
answer = models.CharField(max_length=70)
class Response(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='responses')
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.ForeignKey(Answer, on_delete=models.CASCADE)
Each question has multiple answers but each user can only pick one answer to each question.
Each user can answer multiple questions.
I have a ViewSet that authenticated users can access that is supposed to return a list of users with the same answers as them.
serializer_class = serializers.ProfileSerializer
def get_queryset(self):
user_answers = qmodels.Answer.objects.filter(response__user=self.request.user)
return models.Profile.objects.prefetch_related(
Prefetch(
'user__responses',
queryset=qmodels.Response.objects.filter(answer__in=user_answers),
to_attr='common_answers'
)
)
class ProfileSerializer(serializers.ModelSerializer):
common_answers = ResponseSerializer(many=True)
However, I'm getting the following error:
Got AttributeError when attempting to get a value for field `common_answers` on serializer `ProfileSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Profile` instance.
Original exception text was: 'Profile' object has no attribute 'common_answers'.
I've added a print after prefetch_related and it is showing the base records properly but there is no common_answers field

Select users with common answers to questions

I have four models and a CustomUser table.
class Profile(models.Model):
user = models.OneToOneField(CustomUser, on_delete=models.CASCADE)
class Question(models.Model):
question = models.CharField(max_length=140)
class Answer(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name='answers')
answer = models.CharField(max_length=70)
class Response(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='responses')
question = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.ForeignKey(Answer, on_delete=models.CASCADE)
Each question has multiple answers but each user can only pick one answer to each question.
Each user can answer multiple questions.
How do I select a list of users with a nested list of their common answers to a reference user with just the ORM?
I can think of a hacky solution of retrieving the list of common answers and then a python loop to increment the count for each user but I would like to confine it to the ORM as I need to append this to a parent serializer (UserSerializer -> ResponseSerializer).
We can use a Prefetch object here, like:
from django.db.models import Prefetch
user_answers = Answer.objects.filter(response__user=reference_user)
CustomUser.objects.prefetch_related(
Prefetch(
'response_set',
queryset=Response.objects.filter(answer__in=user_answers),
to_attr='common_answers'
)
)
Now the CustomUsers that arise from this queryset, will have an extra attribute common_answers with Response objects that will contain Responses with an Answer that they share with reference_user.
If you are only looking for users that have at least one common answer with reference_user, you can filter out the others with:
CustomUser.objects.filter(
response__answer__response__user=reference_user
).prefetch_related(
Prefetch(
'response_set',
queryset=Response.objects.filter(answer__in=user_answers),
to_attr='common_answers'
)
).distinct()

Adding security questions to my Django site

I need to ask the user for two security questions and their corresponding answers. The security questions will be provided by me, so it will be some kind of <select>. I created a model to store the user profile named UserProfile. It looks like:
class UserProfile(models.Model):
phone1 = models.CharField(help_text='Primary phone number')
phone2 = models.CharField(help_text='Secondary phone number', blank=True)
...
I could do something like:
SECURITY_QUESTIONS_CHOICES = (
('PN', 'What is your telephone number?'),
('BF', 'What is the full name of your best friend?'),
...
)
and add the following two fields to my model:
question1 = models.CharField(choices=SECURITY_QUESTIONS_CHOICES)
question2 = models.CharField(choices=SECURITY_QUESTIONS_CHOICES)
but I want to be able to modify the list of security questions, so I want it to be a model too.
My question is:
What is the best way of having two fields that point to the same model?
Having only one field (eg. questions) which is a ManyToMany relationship to SecurityQuestion, and restricting the number to 2 in the registration form?
Having two fields (question1 and question2) where each one is a ForeignKey to SecurityQuestion?
I would prefer create a separate model for all security questions. It gives you flexibility.
class SecurityQuestions(models.Model):
class Meta:
db_table = 'security_questions'
id = models.AutoField(primary_key=True)
question = models.CharField(max_length = 250, null=False)
class UserProfile(models.Model):
----
----
user_questions = models.ManyToManyField(SecurityQuestions, through='SecurityQuestionsInter')
class SecurityQuestionsInter(models.Model):
class Meta:
db_table = 'security_questions_inter'
profile = models.ForeignKey(Profile)
security_questions = models.ForeignKey(SecurityQuestions)
answer = models.CharField(max_length = 250, null=False)