Django for ISchoolers: Difference between revisions

imported>Aldeka
No edit summary
imported>Aldeka
Line 523:
* Import the model classes we just wrote:
 
<code>
<code>>>> from qandabear.models import Question, Answer</code>
>>> from qandabear.models import Question, Answer</code>
 
* List all the current Questions:
 
<code>
<code>>>> Question.objects.all()<br>
>>> Question.objects.all()<br>
[]</code>
 
How many questions is this?
 
Zen koan: Can there be an Answer for a Question that doesn’t yet exist?
 
=== Add our first Question ===
 
<code>>>> import datetime<br>
>>> q = Question(text="What is the Weirdest Cookbook Ever?")
# We could specify the value for pub_date as well here, but we don't have to since itwhen we wrote its model definition, we specified that pub_date has a default value (of when the question is created) set in its model definition</code>
 
* Try getting the ID number of our new question 'q' by typing <code>q.id</code>. What happens?
 
* Save the Question instance into the database. You have to call save() explicitly.
 
<code>>>> q.save()</code>
>>> q.save()</code>
 
* Get the id of the Question instance. Because it’s been saved, it has an ID in the database. now!
 
<code>>>> q.id
>>> q.id
1</code>
 
* Access the database columns (Fields, in Django parlance) as Python attributes:
 
<code>>>> q.text<br>
>>> q.text
"What is the Weirdest Cookbook Ever?"<br>
"What is the Weirdest Cookbook Ever?"
>>> q.pub_date<br>
>>> q.pub_date
datetime.datetime(2007, 7, 15, 12, 00, 53)</code>
datetime.datetime(2011, 12, 1, 3, 3, 55, 841929)
</code>
 
* Send the Question back in time:
 
<code># Change values by changing the attributes, then calling save().<br>
>>> q.pub_date =import datetime.datetime(2007, 4, 1, 0, 0)<br>
>>> q.pub_date = datetime.datetime(2011, 4, 1, 0, 0)<br>
>>> q.save()<br>
>>> q.pub_date<br>
Line 581 ⟶ 590:
# ...
def __unicode__(self):
# return the answer text, or if the text is longer than 37 characters, return a summary with an ellipsis
summary = self.answer[:37]
ifsummary = len(self.answer) > text[:37:]
if len(self.text) > 37:
summary = summary + '...'
return summary</code>
 
It’s important to add __unicode__() methods to your models, not only for your own sanity when dealing with the interactive prompt, but also because objects’if representationsyou areuse used throughout Django’sDjango's automatically-generated admin, these representations are used there too.
 
(If you’re using to Python programming from a time in the past, you might have seen __str__(). Django prefers you use __unicode__() instead.)
 
=== Adding custom methods to models ===
 
Enough of these normal python methods! Let's build in some useful functionality to our models in qandabear/models.py.
 
<code>import datetime
Line 601 ⟶ 609:
return self.pub_date.date() == datetime.date.today()</code>
 
Note the addition of <code>import datetime</code> to reference Python’s standard datetime module. This allows us to use the datetime library module in models.py by calling it with datetime.
 
* Save these changes to the models.py file.
Line 609 ⟶ 617:
Start a new Python interactive shell by running python manage.py shell:
 
<code>
>>> from polls.models import Poll, Choice
>>> from qandabear.models import Question, Answer
Verify our __unicode__() addition worked:
>>> PollQuestion.objects.all()
[<Question: What is the Weirdest Cookbook Ever?>]
Search your database using the filter method on the objects attribute of Question.
>>> questions = Question.objects.filter(text="What is the Weirdest Cookbook Ever?")
>>> questions
[<Poll: What is the Weirdest Cookbook Ever?>]
>>> questions[0].id # remember python lists start with element 0.
Search your database using the filter method on the objects attribute of Poll.
>>> polls = Poll.objects.filter(question="What is the Weirdest Cookbook Ever?")
>>> polls
[<Poll: What is the Weirdest Cookbook Ever?>]
>>> polls[0].id # remember python lists start with element 0.
1
</code>
If you try to search for a poll that does not exist, filter will give you the empty list. The get method will always return one hit, or raise an exception.
>>> Poll.objects.filter(question="What is the Weirdest Cookbook Ever?")
[]
 
If you try to search for a question that does not exist, filter will give you the empty list. The get method will always return one hit, or raise an exception.
>>> Poll.objects.get(id=1)
 
<Poll: What is the Weirdest Cookbook Ever?>
<code>
>>> Poll.objects.get(id=2)
>>> Question.objects.filter(text="Who framed Roger Rabbit?")
[]
>>> Question.objects.get(id=1)
<Question: What is the Weirdest Cookbook Ever?>
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: PollQuestion matching query does not exist.
</code>
Add Choices
 
===Add Answers===
Observe, there is a Poll in the database, but it has no Choices.
 
>>> p = Poll.objects.get(id=1)
Observe: there is a Question in the database, but it has no Answers! Let's fix that.
>>> p.choice_set.all()
 
<code>
>>> q = Question.objects.get(id=1)
>>> q.answer_set.all()
[]
Create three choicesanswers:
>>> pq.choice_setanswer_set.create(choicetext='To Serve Man', votes=0)
<ChoiceAnswer: To Serve Man>
>>> pq.choice_setanswer_set.create(choicetext='The Original Road Kill Cookbook', votes=0)
<ChoiceAnswer: The Original Road Kill Cookbook>
>>> ca = pq.choice_setanswer_set.create(choicetext='Mini-Mart A La Carte', votes=0)
>>> ca
<ChoiceAnswer: Mini-Mart A La Carte>
</code>
Go in reverse! Find the poll a particular choice belongs to:
 
>>> c.poll
Go in reverse! Find the question a particular answer belongs to:
<Poll: What is the Weirdest Cookbook Ever?>
 
Because a Poll can have more than one Choice, Django creates the choice_set attribute on each Poll. You can use that to look at the list of available Choices, or to create them.
<code>
>>> p.choice_set.all()
>>> a.question
[<Choice: To Serve Man>, <Choice: The Original Road Kill Cookbook>, <Choice: Mini-Mart A La Carte>]
<Question: What is the Weirdest Cookbook Ever?>
>>> p.choice_set.count()
</code>
 
Because a Question can have more than one Answer, Django creates the answer_set attribute on each Question. You can use that to look at the list of available Answer, or to create them.
 
<code>
>>> q.answer_set.all()
[<Answer: To Serve Man>, <Answer: The Original Road Kill Cookbook>, <Answer: Mini-Mart A La Carte>]
>>> q.answer_set.count()
3
</code>
No really. Can one be a Choice for a Poll that doesn’t yet exist?:
 
>>> koan = choice("Is this even a choice")
Can one be a Answer for a Question that doesn’t yet exist?:
>>> koan.poll_id
 
>>> koan.poll
<code>
>>> koan = Answer("Is this even an answer")
>>> koan.question_id
>>> koan.question
</code>
 
<!--- Adding pre-written data would go here. -->
 
=== Changing your models ===
 
Oh no! Our client, LulzTech, has decided to change the spec for this prototype. Two changes, in fact. First, they've decided that tracking the pub_date of Questions is silly, and they want to remove that field. Second, they want to add a votes field to each Answer, to track how many upvotes it has. Which means we’re going to have to change our models.
 
* Open qandabear/models.py and edit the Question class:
 
<code>
class Question(models.Model):
question = models.CharField(max_length=200)
</code>
 
* Edit the Answer class too:
 
<code>
class Answer(models.Model):
question = models.ForeignKey(Question)
text = models.TextField()
votes = models.IntegerField(default=0)
pub_date = models.DateTimeField(auto_now_add=True)
</code>
 
The default parameter lets us set a default value for this field if an answer's vote count isn't explicitly specified. Most new answers are going to have zero votes, so we set our default to 0.
 
* Make a migration so the database knows we deleted Question.pub_date and added Answer.votes:
 
<code>
$ python manage.py schemamigration qandabear --auto
</code>
 
* Apply the migration.
 
<code>
$ python manage.py migrate qandabear
</code>
 
===Save and commit===
 
You know the drill!
 
== Database migrations and South, part two ==
Anonymous user