I used the Django tutorial in the official docs to build that polling web app.
I completed most of it. I kinda struggled my way through the automated testing tutorial. Maybe as my experience with Python increases, writing robust testing elements to my apps will become easier. But all the code is in place and working. I’ve also extended it with some additional basic features.
Backtracking to tutorial #02 - - for the Playing with API section - - I have a question. This part of the tutorial teaches how to query, add, delete, and save these changes to rows and columns from the db.sqlite3 database.
For example, here is how I activate my shell, import the models and classes, and then print out their contents:
$ python manage.py shell
Python 3.10.5 (main, Jun 6 2022, 18:49:26) [GCC 12.1.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from polls.models import Choice, Question
>>> Question.objects.all()
<QuerySet [<Question: What's up?>, <Question: How many elected politicians does it take to change a light bulb?>, <Question: What generation do you belong to?>]>
>>> Choice.objects.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just building my website again>, <Choice: Huh?>, <Choice: Lost Gen : 1883-1900>, <Choice: Greatest Gen : 1901-1927>, <Choice: Silent Gen : 1928-1945>, <Choice: Baby Boomers : 1946-1964>, <Choice: Generation X : 1965-1980>, <Choice: Millenials : 1981-2001>, <Choice: Zoomers : 2002-2020>, <Choice: Undefined yet : 2021-current>]>
Next is how I query stored Choices
and Questions
specified by their unique identifier:
>>> Question.objects.filter(id=4)
<QuerySet [<Question: What generation do you belong to?>]>
>>> Choice.objects.filter(id=4)
<QuerySet [<Choice: Huh?>]>
Below is me instantiating a Question (with primary key = 3) and adding 4 unique Choices:
>>> q = Question.objects.get(pk=3)
>>> q
<Question: How many elected politicians does it take to change a light bulb?>
>>> q.choice_set.create(choice_text="One?", votes=0)
<Choice: One?>
>>> q.choice_set.create(choice_text="Two?", votes=0)
<Choice: Two?>
>>> q.choice_set.create(choice_text="Ten?", votes=0)
<Choice: Ten?>
>>> q.choice_set.create(choice_text="None! Elected politicians never change anything!", votes=0)
<Choice: None! Elected politicians never change anything!>
>>> q.choice_set.create(question_if)
So that all works. I understand all of that. For the choice_set
mechanism, the explanation in the official Django doc is sparse but I found an interaction on Stack Overflow which fills that knowledge gap titled: What is choice_set in this Django app tutorial?
How do I change one of the choice_text’s that is already created above? I have already got two answers to that question: I can use the Admin Dashboard user interface, find the entry, change it, then click the green “Save” button. Alternatively, I can use my sqlitebrowser
utility and manually change the entry. But my question is: How do I change an existing choice_text
from the CLI shell?
Here are some of my futile attempts:
>>> q.choice_set.modify(choice_text="None!")
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'RelatedManager' object has no attribute 'modify'
>>> q.choice_set.change(choice_text="None!")
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'RelatedManager' object has no attribute 'change'
>>> q.choice_modify.filter(choice_text="Ten?", votes=0)
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Question' object has no attribute 'choice_modify'
>>> q.choice_change.filter(choice_text="Ten?")
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: 'Question' object has no attribute 'choice_change'
>>> q.choice_change.filter(choice_text="Ten?")
Any ideas on how to change / modify choice text that is already entered into the database?
For your reference, here is the views.py
:
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Choice, Question
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
class DetailView(generic.DetailView):
model = Question
template_name = 'polls/detail.html'
class ResultsView(generic.DetailView):
model = Question
template_name = 'polls/results.html'
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 += 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,)))
class AboutView(generic.TemplateView):
template_name = "polls/about.html"
And my models.py:
from django.db import models
from django.utils import timezone
import datetime
class Question(models.Model):
question_text = models.CharField(max_length=200)
title_text = models.CharField(max_length=200, blank=True)
pub_date = models.DateTimeField('date published')
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
def __str__(self):
return self.question_text
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE,)
choice_text = models.CharField(max_length=200)
notes = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text