dragonmnl
dragonmnl

Reputation: 15548

Django's Generic Views: how to filter get_queryset based on foreign class attributes?

I've been following Django starter tutorial ( https://docs.djangoproject.com/en/1.8/intro/tutorial05/ )

I decided to make some modifications to test my skills as of now.

Specifically I intend to implement a custom get_queryset for ResultsView generic view.

Something like this:

# views.py
class ResultsView(generic.DetailView):
    model = Question
    template_name = 'polls/results.html'

    def get_queryset(self):
        '''
        Make sure we are displaying results for choices which have 1+ votes
        '''
        return Question.objects.get ...

Basically my goal is to return Questions' choices only for choices with at least 1 vote.

So I tried in Django's shell something like this:

# Django shell
q = Question.objects.get(pk=1)
q.choice_set.filter(votes=1)
[<Choice: Not much>]

Here I get question with pk = 1, then filter based on choice_set (of Choice model, whose fk refers to Question model).

I'm trying to figure out how to implement this in my views.py, so that it returns Questions' content (i.e. choices) only for choices with 1+ votes (i.e. displaying all choices with related votes but choices with 0 votes).

Just for completeness here is the actual template (polls/results.html):

<h1>{{ question.question_text }}</h1>

<ul>
{% for choice in question.choice_set.all %}
    <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li> {# pluralize used to automatically add "s" for values with 0 or 2+ choice.votes #}
{% endfor %}
</ul>

<a href="{% url 'polls:detail' question.id %}">Vote again?</a>

Models

# models.py
Class Question(models.Model): 

    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):             
        return self.question_text

    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now

class Choice(models.Model):
    question = models.ForeignKey(Question)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self): 
        return self.choice_text

Upvotes: 1

Views: 5910

Answers (1)

bwarren2
bwarren2

Reputation: 1387

I think __ relations should do you.

Something like this maybe?

def get_queryset(self):

    return Question.objects.filter(choices__votes__gte=1)

EDIT:

You actually want to overload get_object. See the definitions of get() and get_object here: https://ccbv.co.uk/projects/Django/1.8/django.views.generic.detail/DetailView/

Specifically, something like:

pk = self.kwargs.get(self.pk_url_kwarg, None)
Choice.objects.filter(question__pk=pk, votes__gte=1)

What you are doing is a little weird because detail view usually works on one object, but this should work.

Upvotes: 3

Related Questions