0

I've been working my way through the Django tutorial, I'm on part 5 where it asks me to create a test to see if polls without choices are being published or not. For every other test we did, like making sure only polls in the past (and not the future) were published we would simply create two polls: one with a pub_date in the past and one in the future:

def test_index_view_with_future_poll_and_past_poll(self):
        """
        Even if both past and future polls exist, only past polls should be
        displayed.
        """

        create_poll(question='past poll', days=-30)
        create_poll(question='future poll', days=30)
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(
            response.context['latest_poll_list'],
            ['<Poll: past poll>'])

For the corresponding view we simply added the following function:

def get_queryset(self):
    """Return the last five published poll."""
    #Returns polls published at a date the same as now or before
    return Poll.objects.filter(pub_date__lte=timezone.now()).order_by('pub_date')[:5]

It just uses the filter() function to filter out any polls with a pub_date in the future, which is simple really. But I can't seem to do the same for polls without any choices, this is what I have so far for the testing function:

class PollsAndChoices(TestCase):
    """ A poll without choices should not be displayed
    """
    def test_poll_without_choices(self):
        #first make an empty poll to use as a test
        empty_poll = create_poll(question='Empty poll', days=-1)
        poll = create_poll(question='Full poll',days=-1)
        full_poll = poll.choice_set.create(choice_text='Why yes it is!', votes=0)
        #create a response object to simulate someone using the site
        response = self.client.get(reverse('polls:index'))
        self.assertQuerysetEqual(response.context['latest_poll_list'], ['<Poll: Full poll>'])

And this is what I have for the related view:

class IndexView(generic.ListView):
    #We tell ListView to use our specific template instead of the default just like the rest
    template_name = 'polls/index.html'
    #We use this variable because the default variable for Django is poll_list
    context_object_name = 'latest_poll_list'

    def get_queryset(self):
        """Return the last five published poll."""
        #Returns polls published at a date the same as now or before
       return Poll.objects.filter(pub_date__lte=timezone.now()).order_by('pub_date')[:5]

    def show_polls_with_choices(self):
       """ Only publish polls that have choices """
       #Since choice_set displays a list we can use it to make sure a poll with an empty list
       #is not published
        for poll in Poll.objects.all():
            if poll.choice_set.all() is not []:
                return poll

Basically nothing is happening, the test is failing:

Traceback (most recent call last):
  File "C:\Users\ELITEBOOK\dropbox\programming\mysite\polls\tests.py", line 125, in    test_poll_without_choices
    self.assertQuerysetEqual(response.context['latest_poll_list'], ['<Poll: Full poll>'])
  File "C:\Users\Elitebook\Dropbox\Programming\virtualenvs\project\lib\site-  packages\django\test\testcases.py", line 829
, in assertQuerysetEqual
    return self.assertEqual(list(items), values)
AssertionError: Lists differ: ['<Poll: Empty poll>', '<Poll:... != ['<Poll: Full poll>']

First differing element 0:
<Poll: Empty poll>
<Poll: Full poll>

First list contains 1 additional elements.
First extra element 1:
<Poll: Full poll>

- ['<Poll: Empty poll>', '<Poll: Full poll>']
+ ['<Poll: Full poll>']

So the app is still publishing both the empty poll and the full poll, is there a way to use the filter() method to refine polls based on whether or not they have choices?

Amon
  • 2,725
  • 5
  • 30
  • 52

3 Answers3

2
def show_polls_with_choices(self):    
    return Poll.objects.exlude(choice_set__isnull=True)


def get_queryset(self):
    """Return the last five published NOT EMPTY polls."""
    #Returns polls published at a date the same as now or before
    return self.show_polls_with_choices().filter(pub_date__lte=timezone.now()).order_by('pub_date')[:5]
madzohan
  • 11,488
  • 9
  • 40
  • 67
  • I'm still getting the same error, poth of the polls are being published. Do you see anything wrong with my test code? – Amon Nov 09 '14 at 22:27
  • 1
    it said `['', '']` so one list != another list, first one you get from `get_queryset` of the view it is `['', '']` and second one you manually declared in your test `['']` – madzohan Nov 09 '14 at 23:22
  • 1
    so if you want get only `['']` you have to edit your `get_queryset` something like that `return self.show_polls_with_choices().filter(pub_date__lte=timezone.now()).order_by('pub_date')` – madzohan Nov 09 '14 at 23:28
  • Hey thanks, that line helped a lot. But another problem is that the rest of the tests create polls without choices for their respective tests. So it was causing this test to fail as well. – Amon Nov 17 '14 at 02:18
2
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'

def get_queryset(self):
    return Polls.objects.exclude(choice__isnull=True).filter(pub_date__lte=timezone.now()).order_by('-pub_date')[:10]

That's probably the easiest way to solve the problem since it combines both; your function and the get_queryset which is necessary for the view to work

And if it's used for the IndexView you need to create at least one choice in the test which you are running on the Index View

muensch
  • 21
  • 3
0

Here is how I did:

def create_question(question_text, days):
    """
    Create a question with the given `question_text` and pulished the
    given number of `days` offset to now(negative for questions
    published in the past, positive for questions that have yet to be published).
    """
    time = timezone.now() + datetime.timedelta(days=days)
    return Question.objects.create(question_text=question_text, pub_date=time)

def create_choice(question_text, days, choice_text=0):
    """
    Createing a question and choice with giver informations
    """
    question = create_question(question_text, days)
    if choice_text:
        question.choice_set.create(choice_text=choice_text, votes=0)
        return question
    else:
        return question

The two above function makes question and choices. And here is the Test Part:


    def test_no_choice(self):
        """
        Will rise a 404 not found if the question hadnt any choice.
        """
        no_choice = create_choice(question_text="No Choice.", days=-2)
        url = reverse('polls:result', args=(no_choice.id,))
        response = self.client.get(url)
        self.assertEqual(response.status_code, 404)

    def test_with_choice(self):
        """
        Will show the choice_text if thers was some.
        """
        question = create_choice(question_text='With Choice.', days=-2, 
        choice_text='With Choice')
        url = reverse('polls:result', args=(question.id,))
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

Moreover, you helped me to finish the filtering part so its 50/50

Besmella
  • 1
  • 1