Django for ISchoolers: Difference between revisions
Content added Content deleted
imported>Aldeka No edit summary |
imported>Aldeka |
||
Line 523: | Line 523: | ||
* Import the model classes we just wrote: |
* 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: |
* List all the current Questions: |
||
<code> |
|||
<code>>>> Question.objects.all()<br> |
|||
>>> Question.objects.all()<br> |
|||
[]</code> |
[]</code> |
||
How many questions is this? |
How many questions is this? |
||
Zen koan: Can there be an Answer for a Question that doesn’t yet exist? |
Zen koan: Can there be an Answer for a Question that doesn’t yet exist? |
||
=== Add our first Question === |
=== Add our first Question === |
||
<code |
<code> |
||
>>> q = Question(text="What is the Weirdest Cookbook Ever?") |
>>> 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 |
# We could specify the value for pub_date as well here, but we don't have to since when we wrote its model definition, we specified that pub_date has a default value (of when the question is created)</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. |
* Save the Question instance into the database. You have to call save() explicitly. |
||
< |
<code> |
||
>>> q.save()</code> |
|||
* Get the id of the Question instance. Because it’s been saved, it has an ID in the database |
* Get the id of the Question instance. Because it’s been saved, it has an ID in the database now! |
||
<code> |
<code> |
||
>>> q.id |
|||
1</code> |
1</code> |
||
* Access the database columns (Fields, in Django parlance) as Python attributes: |
* Access the database columns (Fields, in Django parlance) as Python attributes: |
||
<code |
<code> |
||
>>> 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: |
* Send the Question back in time: |
||
<code># Change values by changing the attributes, then calling save().<br> |
<code># Change values by changing the attributes, then calling save().<br> |
||
>>> |
>>> import datetime<br> |
||
>>> q.pub_date = datetime.datetime(2011, 4, 1, 0, 0)<br> |
|||
>>> q.save()<br> |
>>> q.save()<br> |
||
>>> q.pub_date<br> |
>>> q.pub_date<br> |
||
Line 581: | Line 590: | ||
# ... |
# ... |
||
def __unicode__(self): |
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] |
|||
summary = self.text[:37] |
|||
if len(self.text) > 37: |
|||
summary = summary + '...' |
summary = summary + '...' |
||
return summary</code> |
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 |
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 if you use Django'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 === |
=== Adding custom methods to models === |
||
Enough of these normal python methods! Let's build in some useful functionality to our models. |
Enough of these normal python methods! Let's build in some useful functionality to our models in qandabear/models.py. |
||
<code>import datetime |
<code>import datetime |
||
Line 601: | Line 609: | ||
return self.pub_date.date() == datetime.date.today()</code> |
return self.pub_date.date() == datetime.date.today()</code> |
||
Note the addition of import datetime to reference Python’s standard datetime module. This allows us to use the datetime library module in models.py by calling it with datetime. |
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. |
* Save these changes to the models.py file. |
||
Line 609: | Line 617: | ||
Start a new Python interactive shell by running python manage.py shell: |
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: |
Verify our __unicode__() addition worked: |
||
>>> |
>>> Question.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?>] |
[<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 |
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): |
Traceback (most recent call last): |
||
... |
... |
||
DoesNotExist: |
DoesNotExist: Question 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 |
Create three answers: |
||
>>> |
>>> q.answer_set.create(text='To Serve Man') |
||
< |
<Answer: To Serve Man> |
||
>>> |
>>> q.answer_set.create(text='The Original Road Kill Cookbook') |
||
< |
<Answer: The Original Road Kill Cookbook> |
||
>>> |
>>> a = q.answer_set.create(text='Mini-Mart A La Carte') |
||
>>> |
>>> a |
||
< |
<Answer: 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 |
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 == |
== Database migrations and South, part two == |