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()
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.
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.
I have model for question:
class Question(models.Model):
user = models.ForeignKey(User)
title = models.CharField(max_length=120)
description = models.TextField()
answers = models.ManyToManyField('Answer',related_name='answer_name', blank=True)
post_date = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.title
And I have model for answer:
class Answer(models.Model):
user = models.ForeignKey(User)
question = models.ForeignKey(Question)
ans_body = models.TextField()
post_date = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.ans_body
Question creation and answer submission are working perfectly. I cant correctly show answer for particular question. But when I try to get the count of answer for particular question its not showing. It displays 0 count.
In my view I am getting the list of the answer by:
context["question_list"] = Question.objects.all()
And in my template
{% for question in question_list %}
{{ question.title }}
Ans:{{question.answers.count}}
{% endfor %}
When I do this I get the count 0 if there are answers. How can I get the count of the answers for particular questions.
This worked:
{{question.answer_set.count}}
Happy..
You can do something like {{ question.answers.all.count }}, but if you are iterating over more than question it will cause a database query for every question.
If you want to annotate the whole queryset with the count for each question:
from django.db.models import Count
context['question_list'] = Question.objects.all().annotate(
answer_count=Count('answers')
)
Then you can access the count for each question with {{ question.answer_count }}.
Why not use: Question.objects.all().count()
For my project, I have a Field in 'Info' Model
users_like = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="%(app_label)s_%(class)s_likes", blank=True)
I use below code to count the number of like then show it in Admin List Page.
# admin.py
from django.contrib import admin
from .models import Info
class InfoAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'like_count',)
def like_count(self, obj):
return obj.users_like.all().count()
admin.site.register(Info, InfoAdmin)
The result is:
Hope these can help you!
This will work for you without any problem in your case:
{{question.answer_name.count}}
I have a model as followed:
class Venture(models.Model):
name = models.CharField(_('name'), max_length=255)
created = models.DateTimeField(editable=False)
modified = models.DateTimeField()
class QuestionSet(models.Model):
title = models.CharField(_(u'title'), max_length=100)
class Question(models.Model):
title = models.CharField(_(u'title'), max_length=255)
qset = models.ForeignKey(QuestionSet, related_name='questions')
class Answer(models.Model):
question = models.ForeignKey(Question, related_name='answers')
responder = models.ForeignKey(User)
venture = models.ForeignKey(Venture, related_name='answers')
text = models.TextField(_(u'answer'), blank=True, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
There exists a set of predefined questions for all users. For each Venture, I have a page for each QuestionSet which lists the Questions in that set and I loop over the questions as followed:
<div> {{ venture.name }} </div>
{% for question in qset.questions.all %}
<div class="qset-question control-group">
{{ question.title }}
{# How do I access the answer for the current venture? #}
</div>
{% endfor %}
The question is what is the best way to get the Answer of that Question for the current venture. I want to output some information about the answer here.
Any help is appreciated.
I solved the problem by creating a custom template tage. Here is the code:
#register.assignment_tag
def question_answer(venture, question):
answers = question.answers.filter(venture=venture)
return answers[0] if answers else None
then used it like this:
{% question_answer venture question as answer %}
{{ answer }}
The simplest solution would be to do a select on Answer for a given 'venture', which will give you a list of Answers. You can then use this to get all the questions for a venture.
So something like this:
ans = Answer.objects.filter(venture=v)
Edit::
Based on what you have said you need to rework your model. There are a number of short coming that I can see (i will let you figure it out). Else you need to do more than one query and give your view multiple query sets.
What about something like this?
models.py
from django.db import models
from django.contrib.auth import get_user_model
from django.utils.translation import ugettext as _
User = get_user_model()
class Venture(models.Model):
name = models.CharField(_('name'), max_length=255)
created = models.DateTimeField(auto_now_add=True, editable=False)
modified = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Question(models.Model):
title = models.CharField(_(u'title'), max_length=255)
def __str__(self):
return self.title
class VentureQuestion(models.Model):
venture = models.ForeignKey('Venture', related_name='questions')
question = models.ForeignKey('Question', related_name='venture_questions')
def __str__(self):
return "{}: {}".format(self.venture, self.question)
class Answer(models.Model):
question = models.ForeignKey('VentureQuestion', related_name='answers')
responder = models.ForeignKey(User, related_name='answers')
text = models.TextField(_(u'answer'), blank=True, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return "{}: {}".format(self.responder.username, self.text)
admin.py
from django.contrib import admin
from example.models import Venture, VentureQuestion, Question, Answer
class AnswerInline(admin.StackedInline):
model = Answer
extra = 0
class VentureQuestionAdmin(admin.ModelAdmin):
inlines = [AnswerInline]
admin.site.register(Venture)
admin.site.register(VentureQuestion, VentureQuestionAdmin)
admin.site.register(Question)
admin.site.register(Answer)
That way you can have answers for each Question related to a Venture... (It sounds like that's the functionality you are looking for at least...)
>>> from example.models import Venture
>>> ventures = Venture.objects.all()
>>> for venture in ventures:
... for venture_question in venture.questions.all():
... venture_question.question.title
...
u'What is this?'
u'How does this work?'
u'Does this even work?'
>>> for venture in ventures:
... for venture_question in venture.questions.all():
... venture_question.question.title, [answer.text for answer in venture_question.answers.all()]
...
(u'What is this?', [])
(u'How does this work?', [u'It just does!'])
(u'Does this even work?', [u'Sure it does...', u'I think so'])
and you can have another Venture that uses the same Question but has different Answers
>>> venture = Venture.objects.get(name='Another Venture')
>>> for venture_question in venture.questions.all():
... venture_question.question.title, [answer.text for answer in venture_question.answers.all()]
...
(u'What is this?', [])
after adding an Answer to the new VentureQuestion
>>> venture = Venture.objects.get(name='Another Venture')
>>> for venture_question in venture.questions.all():
... venture_question.question.title, [answer.text for answer in venture_question.answers.all()]
...
(u'What is this?', [u"It's another venture with the same question and it's own answers..."])
I have the following database model -
class ObjectDetail(models.Model):
title = models.CharField()
img = models.ImageField()
description = models.TextField()
uploaded_by = models.ForeignKey(User, related_name='uploaded_by')
class Vote(models.Model):
vote_type = models.BooleanField(default = False)
voted_by = models.ForeignKey(User, related_name='voted_by')
voted_for = models.ForeignKey(User, related_name='voted_for')
shared_object = models.ForeignKey(ObjectDetail, null=True, blank=True)
dtobject = models.DateTimeField(auto_now_add=True)
Now, in my views I want to get the number of upvotes and downvotes for each of the objects.
One way of doing it would be to add a function under class ObjectDetails
as follows -
#property
def upvote(self):
upvote = Vote.objects.filter(shared_object__id = self.id,
vote_type = True).count()
return upvote
#property
def downvote(self):
downvote = Vote.objects.filter(shared_object__id = self.id,
vote_type = False).count()
return downvote
But this would, cause two queries for each of the object, present in the database.
Another method would be to use annotate
obj = ObjectDetail.objects.select_related().filter(FILTER_CONDITION).annotate(upvote=Count('vote'), downvote=Count('Vote')).order_by('-shared_time')
The above statement is wrong in a sense that it just gives me the counts of votes, irrespective of upvotes and downvotes.
if you see into the model, you can get upvote by filtering vote__vote_type = True and a downvote by vote__vote_type=False
How to add these two conditions/filters in the query statement?
So my prime objective is to get the two values of upvote and downvote for each of the items, with making least db queries, such that in the template, if i do
{{ obj.upvote }} I can get the number of upvote on the object, and the similar for downvote.
Please let me know, thanks.
Did you try with values() to group the different vote_types?
https://docs.djangoproject.com/en/dev/topics/db/aggregation/#values
Vote.objects.select_related().filter(FILTER_CONDITION).values('shared_object', 'vote_type').annotate(vote_count=Count('vote_type'))
At this point you can use regroup in the template to loop on ObjectDetailss
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#regroup