I'm trying to create a quiz app, i'm a beginner in dajango and rest, and I'm trying to create a serializer for creating new question with choices, i also not understand well how writable nested serializers working, if some one can give a working example
models.py:
class Question(models.Model):
quiz = models.ForeignKey(Quiz, related_name="question")
question = models.CharField(max_length=200)
def __unicode__(self):
return self.question
class Choice(models.Model):
question = models.ForeignKey(Question, related_name="choice")
choice = models.CharField(max_length=200)
correct_answer = models.BooleanField(default=False)
def __unicode__(self):
return self.choice
serializers.py:
class createChoiceSerializer(serializers.ModelSerializer):
class Meta:
model = Choice
fields = ('choice','correct_answer',)
class createQuestionSerializer(serializers.ModelSerializer):
choices = createChoiceSerializer()
class Meta:
model = Question
def create(self, validated_data):
choices_data = validated_data.pop('choices')
question = Choice.objects.create(**validated_data)
for choice in choices_data:
try:
choice = Choice.objects.get(name=choice["name"])
except Choice.DoesNotExist:
choice = Choice.objects.create(**choice)
question.choices.add(choice)
return question
when i write the question and choice i got an error:
ValueError at /questions/create
Cannot assign "u"what's your name"": "Choice.question" must be a "Question" instance.
question = Choice.objects.create(**validated_data)
question is a Choice instance and question.choices.add(choice) basically adds Choice to Choice instance.
You may try Question.objects.create(**validated_data). I'm not sure if this works but at least solves the error you encounter now.
Related
I've these tables:
class ContestQuestions(models.Model):
contest = models.ForeignKey(Contest, on_delete=models.CASCADE,
related_name='contest_question_contest')
quetions = models.ForeignKey(Question, on_delete=models.CASCADE,
related_name='contest_question_questions')
class UserResponse(models.Model):
user = models.ForeignKey(User, on_deleted=models.CASCADE, related_name='user_response')
response = models.ForeignKey(Answer, on_delete=models.CASCADE,
related_name='user_answer')
Other related tables I've:
class Contest(models.Model):
name = charfield
date = charfield
is_active = bool
class Question(models.Model):
title = charfield
created_at = datetimefield
class Answer(models.Model):
question = FK(Question)
answer = charfield #4 options of 1 question
is_true = bool
I need to get some stat about every quiz. So from every quiz, I want to know the top 5 most correctky answered questions and most incorrectly answered questions and total number of people who attempted that question.
How can I write a query for it?
I would add a method to your Contest model so that you can access this data like so:
class Contest(models.Model):
...
def top_answered_questions(self, correct=True):
return Questions.objects.filter(
contest_question_questions__contest=self
).annotate(
correct_answers=Count('answer', filter=Q(answer__is_true=correct))
).order_by(correct_answers)
You can then call contest.top_answered_questions()[:5] and change the correct parameter to get correctly and incorrectly answered questions.
Recently, I start project using django 3 I face the problem with model
I want to create the modelform and the field is a list:
Like answer1, answer2, ..., answer10,...
class Quiz(models.Model):
question = models.CharField(max_length=30)
def __str__(self):
return self.question
quiz = Quiz.objects.all()
class Answer(models.Model):
answer1 = models.CharField(max_length=20)
answer2 = models.CharField(max_length=20)
answer3 = models.CharField(max_length=20)
...
answer10 = models.CharField(max_length=20)
...
How I use loop or something to declare this answer field?
Can I set my table column name of
answer1 = quiz[0].question
Not sure what database you are using, but you could use ArrayField if you are using PostreSQL instead of creating many similar columns.
https://docs.djangoproject.com/en/3.0/ref/contrib/postgres/fields/
I have below two models in my app,
class Question(models.Model):
question_text = models.CharField(max_length=200)
question_author = models.ForeignKey(User, on_delete=models.CASCADE)
q_pub_date = models.DateTimeField('Date Question Published')
def __str__(self):
return self.question_text
class Answer(models.Model):
answer_text = models.CharField(max_length=5000)
answer_author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='ans_auth')
question = models.ForeignKey(Question, on_delete=models.CASCADE)
a_pub_date = models.DateTimeField('Date Answer Published')
def __str__(self):
return self.answer_text
I want to show latest questions on home page in a list. Each item in list will show question text and one answer out of many posted for that particular question. I am able to show question text but I am not able to find a way to get the answer item for every question item in my view below,
def home(request):
latest_question = Question.objects.order_by('-q_pub_date')[:15]
You can access all answers by using the related_name:
>>> question = Question.objects.get(question_text='random question')
>>> print(question.answer_set.all())
You can read more about this on: https://docs.djangoproject.com/en/2.0/ref/models/fields/#django.db.models.ForeignKey.related_name
You could get the answer to a specific question with the reverse relation question_instance.answer_set.all() in views, {{ question_instance.answer_set.all }} in templates.
To select one answer, you can use slice, or first():
{{question_instance.answer_set.all.0 }} # templates
question_instance.answer_set.first() # views
If you want to add a new field votes to the Question and you want the answer which has highest votes?
A property method inside your question model will do it like:
#property
def higher_answer(self):
return self.answer_set.all().order_by('vote').last()
I'm working with the Django tutorial that helps you build a Poll application. I finished all the tutorials and now I´m trying to add some extra features to learn more about django.
I have 2 models Poll and Choice. The model Choice has a foreign key to Polls, so I can have several choices on each poll. What I want to do is to filter the polls that are shown on my index page by removing those that don´t have any choice at all. I think I can do that with the get_queryset method, but I´m not sure how to use the filter method to accomplish this. Can anyone help me with this?
My Models:
from django.utils import timezone
from django.db import models
import datetime
from django.contrib.auth.models import AbstractUser
# Create your models here.
class Poll(models.Model):
question = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __unicode__(self): # Python 3: def __str__(self):
return self.question
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date < now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice_text = models.CharField(max_length = 200)
votes = models.IntegerField(default=0)
def __unicode__(self): # Python 3: def __str__(self):
return self.choice_text
My Index view
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_poll_list'
def get_queryset(self):
"""
Return the last five published polls (not including those set to be
published in the future) and remove polls with no choices.
"""
# Removing Polls with no Choices
#Filtering by recent posts (just one day old)
p= Poll.objects.filter(
pub_date__lte=timezone.now()
).order_by('-pub_date')[:5]
return p
One solution is annotations:
from django.db.models import Count
polls_with_choices = Poll.objects.annotate(num_choices=Count('choice'))
.filter(num_choices__gt=0)
Essentially, the 'annotate' queryset method will generate SQL that adds a computed column to the results of the query. You then filter on the contents of that computed column.
You're right to use the get_queryset method for this. You can exclude any results where there are no choices like this:
p = Poll.objects.filter(pub_date__lte=timezone.now(), choices__isnull=False)
So I have these models Question, Answer, and UserAnswer that make up a quiz. The problem I'm facing is making a form that validates with these models. I have an idea of how to do it but it's not working.
class QAForm(forms.Form):
answers = forms.ChoiceField(label='Question is this', choices=[('Answer1','Answer1'),('Answer2','Answer2')], widget=forms.RadioSelect())
This works for 1 form, not for thousands. How would I modify this code so that users sees all of the user-generated questions & answers as form and can provide their own answer to it.
I have this (it works but I know it's not a good practice):
def questions(request):
queryset = Questions.objects.all()
if request.method =='POST':
a = request.POST['answer']
answer = Answer.objects.get(answer=a)
importance = request.POST['importance']
q = request.POST['question']
question = Questions.objects.get(id=q)
try:
user_answer = UserAnswers.objects.get(owner=request.user, question=question)
user_answer.answer = answer
user_answer.importance = importance
user_answer.save()
except:
user_answer = UserAnswers(owner=request.user, question=question, answer=answer, importance=importance)
user_answer.save()
else:
try:
current = UserAnswers.objects.all().filter(owner=request.user)
except:
current = ''
return render_to_response("questions/base.html", locals(), context_instance=RequestContext(request))
My models:
class Answer(models.Model):
answer = models.CharField(max_length=120)
question = models.ForeignKey('Questions', null=True, blank=True)
def __unicode__(self):
return self.answer
IMPORTANCE = (
('Irrelevant', 'Irrelevant'),
('A Little Important', 'A Little Important'),
('Somewhat Important', 'Somewhat Important'),
('Very Important', 'Very Important'),
('Mandatory', 'Mandatory'),
)
class Questions(models.Model):
owner = models.ForeignKey(User)
question = models.CharField(max_length=300)
importance = models.CharField(max_length=120, choices=IMPORTANCE, null=True, blank=True)
updated = models.DateTimeField(auto_now=False, auto_now_add=True)
timestamp = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.question
class Meta:
verbose_name ='Question'
verbose_name_plural ='Questions'
class UserAnswers(models.Model):
owner = models.ForeignKey(User)
question = models.ForeignKey(Questions)
answer = models.ForeignKey(Answer)
importance = models.CharField(max_length=120, choices=IMPORTANCE)
def __unicode__(self):
return str(self.owner) + " " + str(self.answer) + " " + str(self.importance)
How about this? (Haven't actually tested it, but it should work)
class QuestionForm(forms.ModelForm):
answer = forms.ChoiceField(required=True, widget=forms.RadioSelect())
def __init__(self, question=None, *args, **kwargs):
super(QuestionForm, self).__init__(*args, **kwargs)
self.fields['answer'].choices = [(a.text, a.value) for a in Answer.objects.filter(question=question)]
class Meta:
model = Question
fields = ('text')
Then initiating it like -
q = Question.objects.get(pk=1)
qform = QuestionForm(instance=q)
This can be done when you want just one form. You can use a FormSet if you want thousands of it.
PS: I'm assuming the Answer model has a foreignkey to the Question model and they have already been filled up.
Latest code for your demand. You can try this code :
class QuestionForm(forms.ModelForm):
answer = forms.ChoiceField(required=True, widget=forms.RadioSelect())
def __init__(self, question=None, *args, **kwargs):
super(QuestionForm, self).__init__(*args, **kwargs)
self.fields['answer'].choices = [(a.text, a.value) for a in Answer.objects.filter(question=question)]
class Meta:
model = Question
fields = ('text')
general knowledge