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}}
Related
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 have the following view
class AuthorList(FilterView):
model = Author
filterset_class = AuthorFilter
context_object_name = 'authors'
In the template, one of the field is {{ author.value }}, which is an integer.
What I would like to do is to show the sum of all {{ author.value }} in my template, but in a dynamic way (if some filters are used, the sum is updated with the current Queryset).
I have tried adding extra context with get_context_data but I couldn't find out how to make it in a dynamic way.
EDIT
tried this, still not working:
#property
def get_sum_values(self):
sum_values = self.objects.all().aggregate(Sum('value'))['value__sum']
return sum_values
and in the template: {{ authors.get_sum_values }}
I have also tried to add a print statement in the property, but nothing shows up, so I guess the function is not even loaded.
my models:
class Author(models.Model):
name = models.CharField(max_length=50, blank=True, null=True)
value = models.IntegerField(null=True, blank=True)
Have you tried doing the sum in the model as a function ?
#property
def wallet_amount_guests(self):
data_payments = self.user.earnings_set.filter(transaction_type='g').aggregate(Sum('amount'))['amount__sum']
if data_payments == None:
data_payments = 0
return data_payments
The above is just an example I have used before. You can then call in the html as blah.function_name
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
This is my model:
class Feature(models.Model):
name = models.CharField(max_length=75, blank=True)
order = models.SmallIntegerField()
group = models.ForeignKey(FeatureGroup)
def __unicode__(self):
return self.name
class Meta:
ordering = ['order']
The "Features" are being correctly display in the admin control panel based on the value specified in "order".
I have this in my view:
p = get_object_or_404(Phone.objects.prefetch_related('brand', 'features__feature', 'photo_set'), id=id)
I templates I have {% for feature in phone.features.all %}... {{ feature.feature }} ...
The values are being displayed correctly but in random order.
What's wrong and how can I overcome this problem?
Thanks.
How about the template filter dictsort
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#dictsort
{% for feature in phone.features.all|dictsort:"order" %}