accelerating information technology innovationgsl-archive.mit.edu/.../materials/l3.pdf · 2014. 1....
TRANSCRIPT
Accelerating Information Technology
Innovation
http://aiti.mit.edu/program/philippines-summer-2012/
Philippines Summer 2012 Lecture 3 – Rapid Application Development with Python
June 26, 2012
Agenda
• Introduction to MVC and Django • Django Models • Django Views • Django Templates
2
Google App Engine / Heroku / Your own Webserver
Your Django app
Mobile Web Browser/ Mobile Web App/ Desktop Browser
The Big Picture
What is a Web Application Framework?
• A framework (a.k.a. code libraries) that provides functionality for common components in a website, web app, or web service.
• Eases coding for – Working with forms – Handling HTTP requests – Templates for common HTML layouts – URL mapping – Database communication – Session management – Site security
• Allows you to focus on design and functionality rather than small details.
Mini Quiz
5
• How does a web server work?
• What is the most popular web server?
• What is the most popular mobile web browser?
• What is the W3C? What do they do?
• What is the IETF? What do they do?
Mini Quiz Answers
6
• Via HTTP protocol
• Apache
• Android Robot
• World Wide Web Consortium: They develop standards for the web
• Internet Engineering Task Force: They develop standards for the Internet
Web Application Frameworks
7
Python Web Application Frameworks for Backend
Model-View-Controller (MVC) • A paradigm for organizing code often seen in
web app frameworks • Main idea is:
– Separate the storage and manipulation of data (the model) and the presentation of data (view)
– Use the Controller to communicate between the model and view
• Advantages – Easier to develop and test model and view
independently – Easier for others to understand
Model-View-Controller (MVC) (news site example)
Controller
View Model
• News stories and images in a database
• User comments
• Layout of stories on mobile phone or desktop browser
Send request for a story
Asks the model for the story and
its user comments
Serves requested story
Django
• Web application framework, written in Python • Released 2005 • Began with World Online, that needed to
rapidly develop applications for news sites. • Named after gypsy jazz guitarist Django
Reinhardt (1910-53)
• Follows the Model-View-Controller paradigm
Model-View-Controller (MVC) (news site example with Django)
Controller
View Model
• News stories and images in a database
• User comments
• Layout of stories on mobile phone or desktop browser
Send request for a story
Asks the model for the story and
its user comments
Serves requested story
Model
View
Template
Django Models
13
What is a model? A class describing data in your application with attributes for each data field that you care about
The schema for your data
14
Why use Django models? Avoid direct work with the database
No need to handle database connections, timeouts, etc. Let Django do it for you.
15
Django Fields All you do is define a field type
Ex: active = models.BooleanField()
Django handles the rest: • Bit value in sql database
• Represented as a checkbox on a webpage
• Validation of values
16
Before Models: from django.shortcuts import render_to_response import MySQLdb
def book_list(request): db = MySQLdb.connect(user='me', db='mydb',
passwd='secret', host='localhost') cursor = db.cursor() cursor.execute('SELECT name FROM books ORDER BY name') names = [row[0] for row in cursor.fetchall()]
db.close()
return render_to_response('book_list.html', {'names': names})
After Models:
from django.shortcuts import render_to_response from mysite.books.models import Book
def book_list(request):
books = Book.objects.order_by('name')
return render_to_response('book_list.html', {'books': books})
Django Model Syntax class Musician(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) instrument = models.CharField(max_length=100) def __unicode__(): return last_name+”, “+first_name
class Album(models.Model): name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField() artist = models.ForeignKey(Musician) def __unicode__(): return name
19
Field Options blank: if True, field is allowed to be blank. default is False.
null: if True, empty fields will be stored as NULL in database.
choices: list of 2-tuples, will create a select box instead of CharField
class Foo(models.Model): GENDER_CHOICES = ( ('M', 'Male'), ('F', 'Female'), (‘NS’, ‘Not specified’) ) gender = models.CharField(max_length=2, choices=GENDER_CHOICES)
20
Field Options
default: default value for a field
primary_key: if True, this field is the primary key for the model
unique: if True, this will have to be unique throughout the table
verbose_field_name: provides a human readable file name
21
Django Relationship Fields ForeignKey ( foreign class ) Many-to-one
ManyToManyField (foreign class) Uses a temporary table to join tables together
OneToOneField ( foreign class ) Enforces uniqueness, i.e. foreign key with unique=True
22
Django Model Syntax class Musician(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) instrument = models.CharField(max_length=100) def __unicode__(): return last_name+”, “+first_name
class Album(models.Model): artist = models.ForeignKey(Musician) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField() def __unicode__(): return name
23
Creating Models Manually
24
>>> from music.models import Musician
>>> m1 = Musician(first_name='Jimi', last_name='Hendrix', instrument='guitar')
>>> m1.save()
>>> m2 = Musician(first_name="Eric", last_name=”Clapton”, instrument='guitar')
>>> m2.save()
>>> Musician_list = Musician.objects.all()
>>> Musician_list [<Musician: Hendrix, Jimi>, <Musician: Clapton, Eric>]
#remember the unicode!!
Filtering
25
>>>Musician.objects.filter(first_name=”Jimi”) [<Musician: Hendrix, Jimi>]
>>>Musician.objects.filter(instrument=”guitar”) [<Musician: Hendrix, Jimi>, <Musician: Clapton, Eric>]
#returns a QuerySet, not an individual Model Object
>>>Musician.objects.filter(last_name__contains=”Clap”) [<Musician: Clapton, Eric>]
#double underscore!!
Getting
26
>>>Musician.objects.get(first_name=”Jimi”) <Musician: Hendrix, Jimi>
#returns single object
>>>Musician.objects.get(instrument=”violin”) Error! DoesNotExist
>>>Musician.objects.get(instrument=”guitar”) Error! MultipleObjectsReturned
#use try/except when using “get”.
Ordering
27
>>>Musician.objects.order_by(-last_name) [<Musician: Hendrix, Jimi>, <Musician: Clapton, Eric>]
Easier way: add class Meta to Model class
class Musician(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) instrument = models.CharField(max_length=100)
def __unicode__(): return last_name+”, “+first_name
class Meta: ordering = [-last_name]
More Functionality
28
>>>m1.instrument=”drums” >>>m1.save() #updates ALL rows, could lead to “race” condition
>>>Musicians.objects.filter(id=12).update(instrument=”bass”) #updates only “instrument” row
Chaining
>>>Musicians.objects.filter(instrument="guitar").order_by("-last_name") [<Musician: Hendrix, Jimi>, <Musician: Clapton, Eric>]
Rules of Django Models 1. When you update a model, ALWAYS RUN python manage.py syncdb
2. All classes extend models.Model
3. Models only live in Apps
4. Django doesn't save objects until you call save() method
>>>a1 = Album(...) # a1 is not saved to the database yet! >>>a1.save() # Now it is.
29
Tips for Django Models 1. Keep code clean
2. Always create a __unicode__() method
3. Name your variables well
4. Don’t think too much about the database
30
Django Views
31
Views
• What are they (who did the reading??)
• Views are the logical interface between data (Models) and presentation (Templates)
Hello World
#inside views.py (create it)
from django.http import HttpResponse def hello(request):
return HttpResponse("Hello world“)
# EVERY view takes a request object as first parameter
# EVERY view returns an HttpResponse object
How to hook it up?
#use urls.py
from django.conf.urls.defaults import * from mysite.views import hello urlpatterns = patterns('',
('^hello/$', hello), )
Request Life Cycle 1. A request comes in to /hello/. 2. Django determines the root URLconf by looking at the
ROOT_URLCONF setting. 3. Django looks at all of the URLpatterns in the URLconf
for the first one that matches /hello/. 4. If it finds a match, it calls the associated view function. 5. The view function returns an HttpResponse. 6. Django converts the HttpResponse to the proper HTTP
response, which results in a Web page.
Dynamic Content
from django.conf.urls.defaults import * from mysite.views import hello, current_datetime,
hours_ahead
urlpatterns = patterns('', (r'^hello/$', hello), (r'^time/$', current_datetime),
)
Dynamic Content from django.http import HttpResponse import datetime
def hello(request): return HttpResponse("Hello world")
def current_datetime(request): now = datetime.datetime.now() html = "<html><body>It is now %s.</body></html>" % now return HttpResponse(html)
Dynamic URLs from django.conf.urls.defaults import * from mysite.views import hello, current_datetime,
hours_ahead
urlpatterns = patterns('', (r'^hello/$', hello), (r'^time/$', current_datetime), (r'^time/plus/(\d{1,2})/$', hours_ahead),
)
Dynamic URLs from django.http import Http404, HttpResponse import datetime def hours_ahead(request, offset):
try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset) html = "<html><body>In %s hour(s), it will be %s.</ body></html>" % (offset, dt)
return HttpResponse(html)
A Note about Development
Where to start, views or URLconfs? • Big Picture: Start with URLconfs
– get an idea of what kind of content you need to deliver – to-do list
• Bottom Up: Start with Views – first make the pieces, then put the puzzle together
Tricks with URLconfs
Factor out common prefixes Before:
urlpatterns = patterns('', (r'^one/$', myapp.views.someView), (r'^two/$', myapp.views.someOtherView), (r'^three/$', myapp.views.evenOtherView),
)
Tricks with URLconfs
Factor out common prefixes After:
urlpatterns = patterns(‘myapp.views', (r'^one/$', someView), (r'^two/$', someOtherView), (r'^three/$', evenOtherView),
) urlpatterns+= patterns(‘myotherapp.views’, ….
Extra Parameters to Views # urls.py from django.conf.urls.defaults import * from mysite import views
urlpatterns = patterns('', (r'^listStyle1/$', views.list_view, {'template_name':'template1.html'}),
(r'^listStyle2/$', views.list_view, {'template_name': 'template2.html'}), )
Extra Parameters to Views # views.py from django.shortcuts import render_to_response from mysite.models import MyModel
def list_view(request, template_name): m_list = MyModel.objects.filter(is_new=True) return render_to_response(template_name, {'m_list': m_list})
Extra Parameters to Views # views.py from django.shortcuts import render_to_response from mysite.models import MyModel
def list_view(request, template_name): m_list = MyModel.objects.filter(is_new=True) return render_to_response(template_name, {'m_list': m_list}) ^^ ̂ #this is called TEMPLATE CONTEXT
Generic Views
• Django comes with some commonly used views – redirect a user to another page – render a specific template – display list and detail view of objects – display date-based objects in archive pages
Generic Views #Example: direct_to_template
from django.conf.urls.defaults import * from django.views.generic.simple import direct_to_template
urlpatterns = patterns('', (r'^about/$', direct_to_template, { 'template': 'about.html' })
)
#Magic!!
Loose Coupling
• Changes made to one piece of code should have little or no effect on other pieces of code – to change URL from “/hours_ahead” to “/
plus_hours”, need to change only URLconf – to change View from calculating “hours
ahead” to “hours ago”, need to change only view
– Allows linking multiple URLs to the same view
Loose Coupling def hours_ahead(request, offset):
try: offset = int(offset) except ValueError: raise Http404() dt = datetime.datetime.now() + datetime.timedelta(hours=offset)
html = "<html><body>In %s hour(s), it will be %s.</body></html>" % (offset, dt) return HttpResponse(html)
#HTML should be in a Template!!
Django Templates
50
weather.html <html>
<head> <title> Weather </title> </head>
<body> <p>Today’s weather in {{ city }} is {{ description }}.</p> <div id=“temperature”> {% for day in thisWeek %} <li> On {{ day.date }}, the temperature will be {{ day.temperature }}. </li> {% endfor %}
</div> <div id="ads"> {% block ads %} Click on these ads! {% endblock %} </div> </body> </html>
Today’s weather in Manila is sunny.
• On Thursday, the temperature will be 20.
• On Friday, the temperature will be 25. • On Saturday, the temperature will be
22.
Click on these ads!
city = ‘Manila‘ descrip1on = 'sunny‘ thisWeek = [dict(date='Thursday', temperature=20), dict(date='Friday', temperature=25), dict(date='Saturday', temperature=22)]
Context
Displayed by browser
Syntax template.render(context)
week = [dict(date='Thursday', temperature=20), dict(date='Friday', temperature=25), dict(date='Saturday', temperature=22)]
weather.render({city:‘Manila’, description:’sunny’, thisWeek=week})
Shortcut from Views # views.py from django.shortcuts import render_to_response from mysite.models import MyModel
def list_view(request, template_name): m_list = MyModel.objects.filter(is_new=True) return render_to_response(template_name, {'m_list': m_list})
Templates
• A text-based template for HTML, CSS, XML, JavaScript, etc.
• Mixture between hard-coded text and abstractions
• Abstractions – Variables – Tags
• Re-useable and extensible
Hard-coded Text in weather.html <html>
<head> <title> Weather </title> </head>
<body> <p>Today’s weather in {{ city }} is {{ description }}.</p> <div id=“temperature”> {% for day in thisWeek %} <li> On {{ day.date }}, the temperature will be {{ day.temperature }}. </li> {% endfor %}
</div> <div id="ads"> {% block ads %} Click on these ads! {% endblock %} </div> </body> </html>
Variables
• {{ variable }} – If variable doesn’t exist, then output TEMPLATE_STRING_IF_INVALID (default: empty string “”)
• {{ variable.attribute }} 1. Dictionary Lookup. variable[“attribute”] 2. Attribute Lookup. variable.attribute 3. Method Call. variable.attribute() 4. List-index Call. variable[attribute]
Variables in weather.html <html>
<head> <title> Weather </title> </head>
<body> <p>Today’s weather in {{ city }} is {{ description }}.</p> <div id=“temperature” {% for day in thisWeek %} <li> On {{ day.date }}, the temperature will be {{ day.temperature }}. </li> {% endfor %}
</div> <div id="ads"> {% block ads %} Click on these ads! {% endblock %} </div> </body> </html>
Filters • Modify the output of variables • {{ variable|filter }}
foo := “Hello World” bar := [‘a’, ‘b’, ‘c’]
{{ foo|lower }} --> hello world {{ bar|length }} --> 3 {{ bar|slice:“:2” }} --> [‘a’, ‘b’] {{ some|default:“error!” }} --> error!
Tags
• for loops • if clauses • comments • blocks • and many more built-in tags (look them
up!)
• {% tag %} … {% endtag %}
Tags in weather.html <html>
<head> <title> Weather </title> </head>
<body> <p>Today’s weather in {{ city }} is {{ description }}.</p> <div id=“temperature” {% for day in thisWeek %} <li> On {{ day.date }}, the temperature will be {{ day.temperature }}. </li> {% endfor %}
</div> <div id="ads"> {% block ads %} Click on these ads! {% endblock %} </div> </body> </html>
For loops {% for x in y %} … logic … {% endfor %}
fruit_basket := {‘apples’, ‘oranges’, ‘pineapples’}
{% for fruit in fruit_basket %} <li>{{ fruit }}</li>
{% endfor}
<li>apples</li> --> <li>orange</li> <li>pineapples</li>
If clauses
{% if <condition> %} … logic …
{% else %} … logic …
{% endif %}
{% if rain > 1 } Buy an umbrella for {{ price1 }} {% else %} Buy sunglasses for {{ price2 }} {% endif %}
Comments
{% comment %}
This comment won’t be displayed!
{% endcomment}
• Ignore everything inside tag – For inline comments, use {# blah blah blah #}
Template Inheritance • Define extensible parts of a template with
block tags {% block name %} … {% endblock %} • Create child templates that can extend
blocks • Load parent template with {% extends “parent_template” %}
weather.html <html>
<head> <title> Weather </title> </head>
<body> <p>Today’s weather in {{ city }} is {{ description }}.</p> <div id=“temperature”> {% for day in thisWeek %} <li> On {{ day.date }}, the temperature will be {{ day.temperature }}. </li> {% endfor %}
</div> <div id="ads"> {% block ads %} Click on these ads! {% endblock %} </div> </body> </html>
ads.html
{% extends "weather.html" %} {% block ads %} {% if rain > 1 } Buy an umbrella! {% else %} Buy sunglasses! {% endif %} {% endblock %}
Today’s weather in Manila is sunny.
• On Thursday, the temperature will be 20. • On Friday, the temperature will be 25. • On Saturday, the temperature will be 22.
Click on these ads!
Buy an umbrella!
city = ‘Manila‘ descrip1on = 'sunny‘ thisWeek = [dict(date='Thursday',temperature=20), dict(date='Friday', temperature=25), dict(date='Saturday', temperature=22)] rain = 3
Context
Displayed by browser
Template Inheritance
• In child template, redefine contents of the parent’s block tag – similar to overriding methods in class
inheritance • If a block tag is not redefined, then use
contents of block tag in parent • {{ block.super }} explicitly refers to
contents of block tag in parent
ads.html
{% extends "weather.html" %}
Questions?
71
Lab 3
• Connect to the Postgresql Database server at 10.50.27.31
• Create the models and the views for the mini social networking website FriendBook using Django
72