Jump to content

Django for ISchoolers: Difference between revisions

no edit summary
imported>Aldeka
No edit summary
imported>Aldeka
No edit summary
Line 500:
Great! Now our database file knows about qandabear and its new models, and if we need to change our models, South is set up to handle those changes. We’ll come back to South later.
 
'''IMPORTANT:''' You can't migrate an app if it's already been synced in the database using <code>python manage.py syncdb</code>. But you do need to run syncdb at least once before you use south (since south itself uses syncdb to give itself space in your database). That's why it's super important that when you run syncdb, south should be listed under INSTALLED_APPS, but '''none of your own apps should be''', and after you add your app to INSTALLED_APPS, you '''must not run syncdb again''' until after you've already set up migrations with that app.
 
* Add and commit all your work, including the migrations folder that South generated for you.
 
= Chunk 3 =
 
You know the drill. Switch back to the master branch, pull down all the new code, and create a new branch called my-chunk-3. (Or something else, if you like. Your branch names are up to you!)
 
== Let's add some data (via the Django shell)! ==
 
Now, let’s hop into the interactive Python shell and play around with the free API ("Application programming interface" -- APIs aren't just data doodads that hip web startups provide for you, they're an important concept in software architecture.) that Django gives you. To invoke the Python shell, use this command:
 
<code>python manage.py shell</code>
 
We’re using this instead of simply typing “python”, because manage.py sets up the project’s environment for you. “Setting up the environment” involves two things:
 
# Making sure qandabear (and any other apps you might have) are on the right path to be imported.
# Setting the DJANGO_SETTINGS_MODULE environment variable, which gives Django the path to your settings.py file.
 
Once you’re in the shell, explore the database API:
 
* Import the model classes we just wrote:
 
<code>>>> from qandabear.models import Question, Answer</code>
 
* List all the current Questions:
 
<code>>>> 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 it has a default value (of when the question is created) set in its model definition</code>
 
* 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.
 
<code>>>> q.id
1</code>
 
* Access the database columns (Fields, in Django parlance) as Python attributes:
 
<code>>>> q.text<br>
"What is the Weirdest Cookbook Ever?"<br>
>>> q.pub_date<br>
datetime.datetime(2007, 7, 15, 12, 00, 53)</code>
 
* Send the Question back in time:
 
<code># Change values by changing the attributes, then calling save().<br>
>>> q.pub_date = datetime.datetime(2007, 4, 1, 0, 0)<br>
>>> q.save()<br>
>>> q.pub_date<br>
datetime.datetime(2007, 4, 1, 0, 0)</code>
 
* Ask Django to show a list of all the Question objects available:
 
<code>>>> Question.objects.all()<br>
[<Question: Question object>]</code>
 
===Fix The Hideous Default Representation===
 
Wait a minute! <Question: Question object> is an utterly unhelpful, truly wretched, beyond contemptable representation of this object. Let’s fix that by editing the Question model. Use your text editor to open the polls/models.py file and adding a __unicode__() method to both Question and Answer:
 
<code>class Question(models.Model):
# ...
def __unicode__(self):
return self.text
 
class Answer(models.Model):
# ...
def __unicode__(self):
summary = self.answer[:37]
if len(self.answer) > 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’ representations are used throughout Django’s automatically-generated admin.
 
(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.
 
<code>import datetime
# ...
class Question(models.Model):
# ...
def was_published_today(self):
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.
 
* Save these changes to the models.py file.
 
=== Test that all those changes did something ===
 
Start a new Python interactive shell by running python manage.py shell:
 
>>> from polls.models import Poll, Choice
Verify our __unicode__() addition worked:
>>> Poll.objects.all()
[<Poll: What is the Weirdest Cookbook Ever?>]
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
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?")
[]
 
>>> Poll.objects.get(id=1)
<Poll: What is the Weirdest Cookbook Ever?>
>>> Poll.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Poll matching query does not exist.
Add Choices
 
Observe, there is a Poll in the database, but it has no Choices.
>>> p = Poll.objects.get(id=1)
>>> p.choice_set.all()
[]
Create three choices:
>>> p.choice_set.create(choice='To Serve Man', votes=0)
<Choice: To Serve Man>
>>> p.choice_set.create(choice='The Original Road Kill Cookbook', votes=0)
<Choice: The Original Road Kill Cookbook>
>>> c = p.choice_set.create(choice='Mini-Mart A La Carte', votes=0)
>>> c
<Choice: Mini-Mart A La Carte>
Go in reverse! Find the poll a particular choice belongs to:
>>> c.poll
<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.
>>> p.choice_set.all()
[<Choice: To Serve Man>, <Choice: The Original Road Kill Cookbook>, <Choice: Mini-Mart A La Carte>]
>>> p.choice_set.count()
3
No really. Can one be a Choice for a Poll that doesn’t yet exist?:
>>> koan = choice("Is this even a choice")
>>> koan.poll_id
>>> koan.poll
 
 
== Database migrations and South, part two ==
 
<!--
== Let's auto-populate some data (using a script in the shell)! ==
== Let's auto-populate some data (using a script in the shell)! == -->
 
== Views with actual data ==
 
= Chunk 4 =
 
== Django templates 101 ==
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.