Writing your first Django app: TypeError in Question class?

I’m following the tutorial on Django for building my first app, and there’s a line in the Question class that is throwing a TypeError exception when running it in PyCharm.

Code:

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):
        # This line throws the exception 
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

Exception:

TypeError: '>=' not supported between instances of 'datetime.datetime' and 'float'

Welcome @MihsterRobot !

What version of Django and Python are you using?

How are you running this? (You don’t run models files directly, they’re only supposed to be run within a Django context.)

Hello there, @KenWhitesell! I should’ve been more explicit.

Django version 5.0.6 and Python version 3.11.5. I’m using the Python shell to run the code, not running the models file directly.

The issue arises when I call was_published_recently().

I don’t see the same symptoms in my test site.

Please provide more context regarding what you’re doing and how you’re running this. (What did you execute before making this call?)

@KenWhitesell I created a few Question objects in a previous shell session, and later called q = Question.objects.get(pk=1) and then q.was_published_recently(). I’m not sure what the problem was, but it seems to be working as expected now, and I haven’t changed anything.

One issue persists, though, and it’s that pub_date within was_published_recently() expects type timedelta instead of DateTimeField. This seems to be an issue with the tutorial itself, as I’ve seen a few mentions on various sites, but I haven’t figured out how to rectify it.

What is making you think that?

The tutorial is correct.

What I see more frequently are people using IDEs that aren’t configured correctly for Django or Python or their virtual environment, and so the IDE is showing an error. But that’s an issue with the IDE, not with Django or the tutorial.

@KenWhitesell That’s my mistake. I double checked on Stack Overflow and saw someone mention a ticket being raised for this issue, and assumed it meant that there was a problem with the tutorial itself (the ticket was closed without implementing).

As you said, it’s probably my IDE being configured incorrrectly. Thanks for the help.

Hey there, Ken. I’m having an issue with what’s being displayed when I visit http://127.0.0.1:8000/polls/1/. This is in reference to part 4 of the tutorial, where you should be able to vote and then see an updated results page, but instead I’m only seeing the text “You’re looking at question 1”.

I recently upgraded to PyCharm Professional and enabled Django support, which helped with some previous issues. I also went through every file I’ve edited since the start of the tutorial to check for any mistakes such as extra characters or incorrect casing, but haven’t found any.

Are you referring to the top part of part 4 (where you’re using the view from part 3), or the bottom part where you’re using the DetailView generic view?

Please post your current detail.html template

Verify that you have choices in the database for question 1. You can do this in the shell with the query Choice.objects.filter(question_id=1), or you can look in the admin at the Choice model (if you have that wired-up).

Also verify that you don’t have multiple views defined by the same name in your views.py file. (You should not have two lines with def detail(... nor two lines with class DetailView(...

I’m referring to the top part of 4. Question 1 has two choices in my database, and there are no duplicates in the views.py file.

detail.html file:

<form action="{% url "polls:vote" question.id %}" method="post">
{% csrf_token %}
<fieldset>
    <legend><h1>{{ question.question_text }}</h1></legend>
    {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
    {% for choice in question.choice_set.all %}
        <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
        <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br>
    {% endfor %}
</fieldset>
<input type="submit" value="Vote">
</form>

views.py file:

from django.db.models import F
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

from .models import Choice, Question


def index(request):
    latest_question_list = Question.objects.order_by("-pub_date")[:5]
    context = {"latest_question_list": latest_question_list}
    return render(request, "polls/index.html", context)


def detail(request, question_id):
    return HttpResponse("You're looking at question %s." % question_id)


def results(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, "polls/results.html", {"question": question})


def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST["choice"])
    except (KeyError, Choice.DoesNotExist):
        # Redisplay the question voting form.
        return render(
            request,
            "polls/detail.html",
            {
                "question": question,
                "error_message": "You didn't select a choice.",
            },
        )
    else:
        selected_choice.votes = F("votes") + 1
        selected_choice.save()
        # Always return an HttpResponseRedirect after successfully dealing
        # with POST data. This prevents data from being posted twice if a
        # user hits the Back button.
        return HttpResponseRedirect(reverse("polls:results", args=(question.id,)))

You skipped some steps in part 3. You at least missed the changes to detail at Raising a 404 error

Everything works after making those changes to the detail view. Thanks again.