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
The Big Picture Google App Engine / Heroku / Your own Webserver Mobile Web Browser/ Mobile Web App/ Desktop Browser Your Django app
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 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? 5
Mini Quiz Answers 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 6
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 Send request for a story Asks the model for the story and its user comments View Layout of stories on mobile phone or desktop browser Serves requested story Model News stories and images in a database User comments
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 Send request for a story Asks the model for the story and its user comments Template View Layout of stories on mobile phone or desktop browser Serves requested story Model News stories and images in a database User comments Model
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 () models.booleanfield Ex: active = 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', (' host='localhost passwd='secret', () db.cursor cursor = (' name cursor.execute('select name FROM books ORDER BY names = [row[0] for row in cursor.fetchall()] () db.close ({ names return render_to_response('book_list.html', {'names':
After Models: from django.shortcuts import render_to_response from mysite.books.models import Book def book_list(request): (' Book.objects.order_by('name books = ({ books return render_to_response('book_list.html', {'books':
Django Model Syntax class Musician(models.Model): first_name = models.charfield(max_length=50) last_name = models.charfield(max_length=50) ( models.charfield(max_length=100 instrument = def unicode (): return last_name+, +first_name class Album(models.Model): name = models.charfield(max_length=100) release_date = models.datefield() () models.integerfield num_stars = 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) ( models.charfield(max_length=100 instrument = 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() () models.integerfield num_stars = def unicode (): return name 23
Creating Models Manually >>> 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.objects.all >>> Musician_list = >>> Musician_list [<Musician: Hendrix, Jimi>, <Musician: Clapton, Eric>] #remember the unicode!! 24
Filtering ( 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!! 25
Getting ( 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. 26
Ordering ( 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] 27
More Functionality >>>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>] 28
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 (...) Album >>>a1 = # 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}) ^^^ TEMPLATE CONTEXT #this is called
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>
Context city = Manila descrip1on = 'sunny thisweek = [dict(date='thursday', temperature=20), dict(date='friday', temperature=25), dict(date='saturday', temperature=22)] Displayed by browser 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!
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 %}
Context city = Manila descrip1on = 'sunny thisweek = [dict(date='thursday',temperature=20), dict(date='friday', temperature=25), dict(date='saturday', temperature=22)] rain = 3 Displayed by browser 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!
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