Django for ISchoolers: Difference between revisions

imported>Aldeka
imported>Aldeka
Line 692:
</source>
 
== Database migrations and South, part two ==
<!--- 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, theyThey 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 QuestionAnswer class:
 
<source lang="python">
class Question(models.Model):
question = models.CharField(max_length=200)
</source>
 
* Edit the Answer class too:
 
<source lang="python">
Line 717 ⟶ 710:
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 thewe databasecan knowslet wethe deleteddatabase Question.pub_dateknow andthat we added Answer.votes:
 
<source lang="python">
Line 723 ⟶ 716:
</source>
 
* Apply the migration.
You should get a warning message that looks like this:
 
<source lang="python">
$ python manage.py migrate qandabear
? The field 'Question.pub_date' does not have a default specified, yet is NOT NULL.
Running migrations for qandabear:
? Since you are removing this field, you MUST specify a default
- Migrating forwards to 0002_auto__add_field_answer_votes.
? value to use for existing rows. Would you like to:
> qandabear:0002_auto__add_field_answer_votes
? 1. Quit now, and add a default to the field in models.py
- Loading initial data for qandabear.
? 2. Specify a one-off value to use for existing columns now
No fixtures found.
? 3. Disable the backwards migration by raising an exception.
</source>
 
Success!
South insists on having a default value for this field just in case, even though we're about to remove it. So, let's do that. Enter '2'.
 
===Save and commit===
 
You know the drill!
 
<!--
== Let's auto-populate some data (using a script in the shell)! == -->
 
== Views with actual data ==
 
In Django, each view is responsible for doing one of two things: returning an HttpResponse object containing the content for the requested page, or raise-ing an exception such as Http404.
 
Your view can read records from a database, or not. It can use a template system such as Django’s – or not. It can generate a PDF file, output XML, create a ZIP file on the fly, anything you want, using whatever Python libraries you want. All Django wants is that at the end, it gets an HttpResponse or an exception out of your view function.
 
Most of the Django views in the world use Django’s own database API, which was touched on in the discuss of models, to write or show dynamic data to the user in some fashion. Right now, our views are very simple, and don't use the data in our database at all. Let's fix that.
 
=== Write a better index() view ===
 
To match the spec, our index page should displays the latest 5 questions in the system, separated by commas, according to publication date.
 
* Edit views.py:
 
<source lang="python">
from qandabear.models import Question
? Please enter Python code for your one-off default value.
from django.http import HttpResponse
? The datetime module is available, so you can do e.g. datetime.date.today()
 
def index(request):
latest_qs = Question.objects.all().order_by('-pub_date')[:5]
output = ', '.join([q.text for q in latest_qs])
return HttpResponse(output)
</source>
 
Restart the dev server, and navigate to [http://127.0.0.1:8000/questions/ http://127.0.0.1:8000/questions/]. You should see the text of the last 5 polls (or fewer than five, if you haven't made that many yet).
pub_date is supposed to be a date of some kind. The default may as well be today!
 
There’s a problem here, though: The page’s design is hard-coded in the view. If you want to change the way the page looks, you’ll have to edit this view code. That's silly.
 
* Use Django’s template system to separate the design from Python:
 
<source lang="python">
from django.shortcuts import render_to_response
? Please enter Python code for your one-off default value.
from qandabear.models import Question
? The datetime module is available, so you can do e.g. datetime.date.today()
 
>>> datetime.date.today()
def index(request):
latest_qs = Question.objects.all().order_by('-pub_date')[:5]
context = {'latest_qs': latest_qs}
return render_to_response('qandabear/index.html', context)
</source>
 
To recap what this does:
South will then happily finish creating your migration.
 
* Creates a variable called latest_poll_list. Django queries the database for all Poll objects, ordered by pub_date with most recent first, and uses slicing to get the first five.
* Apply the migration.
* Creates a variable called context that is a dictionary with one key.
* Evaluates the render_to_response function with two arguments, and returns whatever that returns.
render_to_response loads the template called polls/index.html and passes it a value as context. The context is a dictionary mapping template variable names to Python objects.
 
If you can read this this view function without being overwhelmed, then you understand the basics of Django views. Now is a good time to reflect and make sure you do:
 
# What would you have to change to get 10 polls?
# What if you wanted the first 10 by name instead of by publication date?
 
* Reload [http://127.0.0.1:8000/questions/ http://127.0.0.1:8000/polls/]. Now you’ll see an error:
 
<source lang="python">
TemplateDoesNotExist at /questions/
$ python manage.py migrate qandabear
polls/index.html
Running migrations for qandabear:
- Migrating forwards to 0002_auto__add_field_answer_votes__del_field_question_pub_date.
> qandabear:0002_auto__add_field_answer_votes__del_field_question_pub_date
- Loading initial data for qandabear.
No fixtures found.
</source>
 
Ah. There’s no template yet. Let’s make one!
Success!
 
* Make a qandabear/templates/qandabear directory where templates will live. Right alongside the views.py for the qandabear app. This is what I would do:
===Save and commit===
 
<source lang="python">
You know the drill!
mkdir -p qandabear/templates/qandabear
Edit qandabear/templates/qandabear/index.html to contain.
{% if latest_qs %}
<ul>
{% for question in latest_qs %}
<li><a href="/questions/{{ question.id }}/">{{ question.text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No questions are available.</p>
{% endif %}
</source>
 
* Edit TEMPLATE_DIRS in settings.py to have the full path to the templates folder inside your new app. On my computer, this looks like:
== Database migrations and South, part two ==
 
<source lang="python">
<!--
TEMPLATE_DIRS = (
== Let's auto-populate some data (using a script in the shell)! == -->
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
'/karen/Code/django-for-ischoolers/mysite/qandabear/templates',
)
</source>
 
* Reload [http://127.0.0.1:8000/questions/ http://127.0.0.1:8000/questions/] . You should see a bulleted-list containing up to five of your questions. There should also be link pointing to the question's detail page.
== Views with actual data ==
 
*Save and commit.
 
= Chunk 4 =
Anonymous user