63
Epsilon Mobile Pte. Ltd. PYTHON/DJANGO COURSE OUTLINE COURSE OBJECTIVES The primary goal of this course is to provide you basic understandings and skills at Web programming. You will learn Python, Django, HTML/CSS languages and learn how to deploy your own website on a cloud server. Not only knowledge but also practical experiences will be conveyed to you on your behalf. INSTRUCTORS AND CONTACT INFORMATION Tran Dang Khoa Lecturer Email: [email protected] Tel: (+84) 935 667 311 Vo Thanh Loc Assistant Lecturer Email: [email protected] Tel: (+84) 1674 575 320 COURSE METHODOLOGY This course includes lectures, exercises and a final project. This multiplicity of methods allows you to: 1. Test your understandings of theories presented in readings. 2. Use theories to solve the actual problems in organizations. 3. Develop skills in programming, in presentation and in self-studying. This course occurs in a short duration, so the lecturer will guide you to focus on main topics. You also need to reserve your self-studying time to review theories, do exercises and do the final project from the middle time of this course. COURSE MATERIALS AND REFERENCES The course slides prepared by Epsilon Mobile Python Tutorial (Guido van Rossum) http://docs.python.org Django Official Documentation https://docs.djangoproject.com HTML Tutorial (WSC) http://www.w3schools.com/html/

Django - basics

Embed Size (px)

Citation preview

Page 1: Django - basics

Epsilon Mobile Pte. Ltd. PYTHON/DJANGO COURSE OUTLINE

COURSE OBJECTIVES

The primary goal of this course is to provide you basic understandings and skills at Web programming. You will learn Python, Django, HTML/CSS languages and learn how to deploy your own website on a cloud server. Not only knowledge but also practical experiences will be conveyed to you on your behalf.

INSTRUCTORS AND CONTACT INFORMATION Tran Dang Khoa

Lecturer

Email: [email protected]

Tel: (+84) 935 667 311

Vo Thanh Loc

Assistant Lecturer

Email: [email protected]

Tel: (+84) 1674 575 320

COURSE METHODOLOGY

This course includes lectures, exercises and a final project. This multiplicity of methods allows you to:

1. Test your understandings of theories presented in readings.

2. Use theories to solve the actual problems in organizations.

3. Develop skills in programming, in presentation and in self-studying.

This course occurs in a short duration, so the lecturer will guide you to focus on main topics. You also need to reserve your self-studying time to review theories, do exercises and do the final project from the middle time of this course.

COURSE MATERIALS AND REFERENCES

The course slides prepared by Epsilon Mobile

Python Tutorial (Guido van Rossum) http://docs.python.org

Django Official Documentation https://docs.djangoproject.com

HTML Tutorial (WSC) http://www.w3schools.com/html/

Page 2: Django - basics

CSS Tutorial (WSC) http://www.w3schools.com/css/

COURSE SCHEDULE

Duration: September 19th to October 14th, 2011

Time: from 19:00 to 21:00, Monday – Wednesday – Friday each week

Total sessions: 12

Session Topics

1 Python Programming Basics

2 Django Installation and Configuration

3 Models and QuerySets

4 URL Configuration and Request/Response

5 File Uploads and Generic Views

6 HTML and Django Template

7 CSS

8 Forms

9 Deployment under Linux platform (Ubuntu)

10 Admin sites

11 Advanced techniques and Q&A

12 Presentation of final projects

DUCMINHKHOI
Note
Do excersise for download and upload file
Page 3: Django - basics

CREATENEWPROJECTINDJANGO/PYTHON

1. Run: django-admin.py startproject project_name

2. Running the development server: python manage.py runserver

3. Open up settings.py and add these lines at the top:

import os

ROOT_PATH = os.path.dirname(__file__) PROJECT_DIR=os.path.dirname(__file__)

a. If you want to use template folder to store html file, create new folder templates, and

insert these code in settings.py: TEMPLATE_DIRS = (os.path.join(PROJECT_DIR,"templates"))

b. If you want to use static file (css, image, js,..) or media file(video, audio,..) create folder

static and media in project folder and insert these code in settings.py in project folder: MEDIA_ROOT = os.path.join(PROJECT_DIR, '/media/')

MEDIA_URL = '/media/'

STATIC_ROOT = os.path.join(PROJECT_DIR, '/static/')

STATIC_URL = '/static/'

In the urls.py file:

Insert code: from django.contrib.staticfiles.urls import

staticfiles_urlpatterns at the beginning

and code: urlpatterns += staticfiles_urlpatterns()at the end

and add these line:

url(r'^media/(?P<path>.*)$', 'django.views.static.serve',

{'document_root': 'media'}),

c. If you want to add more information about users:

• Declare in settings.py: AUTH_PROFILE_MODULES = 'accounts.UserProfile'

• In models.py: create new class:

UserProfile(models.Model):

# additional information

dob = models.DateField()

# ... many as you wish

User.profile = property(lambda u:

PubProfile.objects.get_or_create(user=u)[0]) # (Tips)

d. If you want to add email sending utility, add these lines in settings.py too:

EMAIL_HOST = 'smtp.gmail.com' #if just test on localhost: = ‘localhost’

Page 4: Django - basics

EMAIL_HOST_USER = '[email protected]'

EMAIL_HOST_PASSWORD = 'yourpass'

EMAIL_PORT = 587 # Check on the Internet if not successful #if just test

#on localhost: = 1025

EMAIL_USER_TLS = True # Gmail now accepts HTTPS only

e. If you want to use Admin feature, uncomment all line related to admin in

INSTALLED_APP in settings.py and URLS.py and re sync the database.

Add these line to urls.py:

from django.contrib import admin

admin.autodiscover()

4. Syncing database:

a. If not have user, create user in mysql:

Login root account in cmd: mysql –u root –p and enter your password

CREATE USER 'newUser'@'%' IDENTIFIED BY 'password';

mysql> GRANT ALL PRIVILEGES ON *.* TO 'newUser'@'%'

-> WITH GRANT OPTION;

CREATE USER 'newUser'@'localhost' IDENTIFIED BY 'password';

mysql> GRANT ALL PRIVILEGES ON *.* TO 'newUser'@'localhost'

-> WITH GRANT OPTION;

b. If not have database to connect, create new database: create database

databaseName (just like in Oracle)

c. Setup database engine through settings.py file

5. If you want, create an App: python manage.py startapp appName

a. Install your app above in settings.py INSTALLED_APPS = {… ‘projectName.appName’}

b. If don’t have: create new urls.py .

add from django.conf.urls.defaults import patterns, include, url

at beginning and urlpatterns = patterns('', …)

and Add url(r’^RegularExpressOfTheHTML/$’, include(name of the fuction)), to the

urls.py of the project directory to show which function to be initialized when a specific

url enter.

c. Create admin.py for app if you want to add some models to you process by admin site:

from django.contrib import admin

from mkcomics.normalpage.models import *

admin.site.register(Comic)

admin.site.register(Issue)

admin.site.register(UserProfile)

Page 5: Django - basics

admin.site.register(Read)

d. Create models.py for app: describe the database

If you want to use table user: Add:

from django import forms

from django.db import models

from django.contrib.auth.models import UserRun: python manage.py

syncdb

e. Interact with database: in the project’s folder, run the command line and run: python

manage.py shell

f. In your app, if you want to use form, create new file forms.py and at the beginning

from django.forms import ModelForm

from django.contrib.auth.models import User

And add: from projectName.appName.models import *

And add: from django import forms at begining

g. In your app, at views.py, implement your function in the urls.py //must have request

parameter

Add the beginning: add from ProjectName.appName.models import *

form ProjectName.appName.forms import *

from django.shortcuts import render_to_response, redirect

from django.template.context import RequestContext

from django.contrib.auth import login, authenticate

from django.contrib.auth.decorators import login_required

from django.http import HttpResponseRedirect

from django.core.mail import send_mail, BadHeaderError

h. Describe your HTML. You can use Django templates and Form to customize your HTML

code. Remember to make block for inheritance as much as possible. Use CSS if you

want.

See your work: go to http://localhost:8000/ to check your project

MTV models in Django:

Model Template

View

Data access Layer

Business Logic Layer

Presentation Layer

Page 6: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

1 | P a g e

SESSION 1 – PYTHON PROGRAMMING BASICS

What is Python? Python is an interpreted, object-oriented, high-level programming language with dynamic semantics. Its

high-level built in data structures, combined with dynamic typing and dynamic binding, make it very

attractive for Rapid Application Development, as well as for use as a scripting or glue language to

connect existing components together. Python's simple, easy to learn syntax emphasizes readability and

therefore reduces the cost of program maintenance. Python supports modules and packages, which

encourages program modularity and code reuse.

Installing Python Official Website: http://www.python.org

Read installation guideline of your OS platform, download source or binary version for your OS and do

steps in the guideline.

Interactive Mode Programming Besides running a source file like other language, Python supports interactive mode programming where

you can type code and invoking the interpreter immediately.

Way 1 – Running Python interpreter from command-line

Page 7: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

2 | P a g e

Way 2 – Running IDLE (Integrated DeveLopment Environment)

Lines and Indentation There are no braces to indicate block of code in Python. Python denotes blocks of code by line

indentation, which enforces very good format of code in practice. Therefore, make code easier to

understand.

Note: The number of spaces in indentation is VARIABLE, but all lines within a block MUST be indented

the same amount. For example, the following code is fine:

However, this will generate an error:

Page 8: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

3 | P a g e

Multi-line Statements Python uses the line continuation character (\) to denote that the line should continue:

However, statements within the [], {}, or () brackets do not need to use line continuation character:

Comments in Python

Standard Data Types There are 5 standard types:

Numbers: support int, long, float and complex.

Page 9: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

4 | P a g e

String: a contiguous set of characters in between quotation marks.

List: a container that holds a number of other objects, even list objects.

Tuple: similar to list but enclosed within parenthese. It is also thought as a read-only list.

Dictionary: consists of key-value pairs.

Page 10: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

5 | P a g e

Condition Statements Combine if, elif and else statements

Loop Statements

Flow-control statements break: terminates the current loop and resumes execution at the next statement.

continue: returns the control to the beginning of the loop.

pass: executes nothing (null operation), used as a placeholder of future code.

Page 11: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

6 | P a g e

Function

For example:

Modules A module allows you to logically organize the Python code by grouping related code into a module to

make the code more understandable and reusable.

Import a module You can use import statement to utilize code of a module. When the interpreter encounters an import

statement, it will attempt to import the module in the search path.

Organize a standard module - Make a new folder which name will be your module name.

- Create a blank file, name it __init__.py (reference more in Python documentation).

- Add your source files (*.py) into this folder.

- Append your module folder path to PYTHONPATH.

Page 12: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

7 | P a g e

Handling exceptions If you have some suspicious code that may raise an exception, place the code in a try: block and except:

statement and finally: statement (optional).

Class

Format of a Class

Class Inheritance Deriving from a base class, the child class inherits all the attributes and can also override data members

and methods from the parent.

Page 13: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

8 | P a g e

Exercises 1. Write a program that continually reads integer numbers from the users until the user inputs value 0.

After that, print out the average value of input numbers.

2. Write a guess number game. Each launching, the program will generate a random lucky number from

1 to 100. After that, the program will ask the user for a guess number. If the guess number is greater

than the lucky number, it will print out “Too high”; if the guess number is less than the lucky number, it

will print out “Too low”. The program will continue to ask a new guess number until the user enters the

lucky number. As a consequence, it will print out “You guess right! It costs you x guesses”, where x is the

number of guesses the user tries.

3. Write a dictionary program (use Dictionary type). When launching, the users can choose 3 options

from the main menu:

a. Search a word

b. Import dictionary

c. Exit

- If the user chooses Search a word, it will require him to enter a word, then, it will print out the

definition of this word and return the main menu.

- If the user chooses Import dictionary, it will require him to enter the path of dictionary file. After that,

it will import words and definitions in the file into the program dictionary. Finally, it returns the main

menu.

- If the user chooses Exit, the program will terminate immediately.

The dictionary file is a plain text file with the following format:

word1

definition1

word2

definition2

Page 14: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

9 | P a g e

4. Write a student management program (use Class). A student has 5 fields of information: ID, Name,

Class, DOB (Date of Birth), GPA (Grade Point Average).

The program will have 4 options from the main menu:

a. Explore all students

b. Add new student

c. Remove a student

d. Exit

- Explore all students: prints out all students with their information.

- Add new student: requires the user to enter the information for new student.

- Remove a student: removes a student by ID.

- Exit: terminates the program.

5. (Plus) Write a mini text-chat (client/server) by using Python networking modules.

Hint: Read Python documentation and use Google to find the necessary modules for your answers.

Requirement Submit your answers for exercises before 00:00 AM on Wednesday, September 21st, 2011 at:

[email protected]

Page 15: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

1 | P a g e

SESSION 2 – Django Installation and Configuration

Overview In order to develop website using Python/Django framework, we currently need to install the following

packages:

1. Python 2.7.x

2. Django 1.x.x

3. MySQL 5.x

4. Python Setuptools

5. MySQL-python-1.2.3

Installing Python 2.7.x Go to the official hompage at http://www.python.org and see the guideline

Installing Django 1.x.x - Go to https://www.djangoproject.com/download/

- Download Django-1.x.x.tar.gz

- Unzip the downloaded file

- Open command-line at folder Django-1.x.x

- Run

Installing MySQL 5.x - Go to http://dev.mysql.com/downloads/

- Install MySQL Community Server (recommend version 5.1.x for Windows 7)

- Install MySQL Workbench

Installing Python Setuptools - Go to http://pypi.python.org/pypi/setuptools#files

- Download your appropriate package (depends on OS). For example, in Windows, we can choose MS

Windows Installer version with the corresponding python version.

Page 16: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

2 | P a g e

- Install the downloaded file. If in debian Linux, you can use .

Installing MySQL-python-1.2.3 - Download MySQL-python at http://sourceforge.net/projects/mysql-python/

- Unzip the download file

- Open command-line at folder MySQL-python-1.2.3

- Run

Note: In Windows, you should download the binary version to install more easily

(http://www.lfd.uci.edu/~gohlke/pythonlibs/)

Creating a Django project - Make sure that Django bin folder appended into PATH.

- Run

- Django Admin Utility will create an empty project structure automatically for you.

__init__.py: An empty file that tells Python that this directory should be considered a Python package.

manage.py: A command-line utility that lets you interact with this Django project in various ways.

settings.py: Settings/configuration for this Django project. urls.py: The URL declarations for this Django project; a "table of contents" of your Django-

powered site.

Running the development server - At the root directory of the project, run python manage.py runserver.

- The development server will be started at 127.0.0.1:8000 (default). You can change the address by

specifying IP:Port at the end of the above command.

- Open 127.0.0.1:8000 in your web browser. You will go to Django-powered default page.

DUCMINHKHOI
Rectangle
DUCMINHKHOI
Rectangle
Page 17: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

3 | P a g e

Workshop: Student Management System This system allows users to add new student information and explore it again.

Creating an App An app is a Web application that does something -- e.g., a Weblog system, a database of public records

or a simple poll app. A project is a collection of configuration and apps for a particular Web site. A

project can contain multiple apps. An app can be in multiple projects.

To create an App, use manage.py utility with startapp command.

Creating models Model in Django is an object-relational mapper in which you describe your database layout in Python

code.

DUCMINHKHOI
Rectangle
Page 18: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

4 | P a g e

Syncing database - Create database named mysite in MySQL.

- Setup database engine in settings.py.

- Install app in settings.py.

DUCMINHKHOI
Rectangle
DUCMINHKHOI
Note
use
Page 19: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

5 | P a g e

- Run

- Review MySQL tables to understand this mechanism.

Configuring URLs - In urls.py at root directory

DUCMINHKHOI
Rectangle
DUCMINHKHOI
Rectangle
DUCMINHKHOI
Note
projectname.app
Page 20: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

6 | P a g e

- Create new urls.py inside sms app folder

Writing your views - In views.py of sms app

- sms/explore.html is a HTML and Django-syntax template

DUCMINHKHOI
Note
always have
DUCMINHKHOI
Note
url to your app
DUCMINHKHOI
Note
recurse until hit primitive end
Page 21: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

7 | P a g e

Writing a template

Exercises 1. Complete the Adding Student feature.

Requirement Submit your answers for exercises before 00:00 AM on Friday, September 23rd, 2011 at:

[email protected]

Page 22: Django - basics

Behind the scenes

• You can use Python – sql statement for insert, update, and delete action:

• If the filter statement isn’t powerful enough, use raw SQL statement

Python – sql equivalent:

command Python sql

Insert into

Or p = Publisher.objects.create()

Django Your apps

Database

Python

SQL

Page 23: Django - basics

Select * from

Select … where

Select … order by

Select … where… order by

Select … where … order by … offset limit

exclude p = Publisher.objects.exclude(name = “O’Reilly”)

update

Return an object, usually with try, catch: try: get() catch(Exception): pass if have many rows, throws Duplicate Exception The condition in get() can use the Field lookup!

Delete

Average,

Page 24: Django - basics

… just like function in SQL

Field lookups

Field lookups are how you specify the meat of an SQL WHERE clause. They're specified as keyword arguments to the QuerySet

methods filter(), exclude() and get().

For an introduction, see models and database queries documentation.

exact

Exact match. If the value provided for comparison is None, it will be interpreted as an SQL NULL (see isnull for more details).

Examples:

Entry.objects.get(id__exact=14)

Entry.objects.get(id__exact=None)

SQL equivalents:

SELECT ... WHERE id = 14;

SELECT ... WHERE id IS NULL;

MySQL comparisons

In MySQL, a database table's "collation" setting determines whether exact comparisons are case-sensitive. This is a database setting, not a

Django setting. It's possible to configure your MySQL tables to use case-sensitive comparisons, but some trade-offs are involved. For more

information about this, see the collation section in thedatabases documentation.

iexact

Page 25: Django - basics

Case-insensitive exact match.

Example:

Blog.objects.get(name__iexact='beatles blog')

SQL equivalent:

SELECT ... WHERE name ILIKE 'beatles blog';

Note this will match 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG', etc.

SQLite users

When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons. SQLite does not

do case-insensitive matching for Unicode strings.

contains

Case-sensitive containment test.

Example:

Entry.objects.get(headline__contains='Lennon')

SQL equivalent:

SELECT ... WHERE headline LIKE '%Lennon%';

Note this will match the headline 'Lennon honored today' but not 'lennon honored today'.

SQLite users

Page 26: Django - basics

SQLite doesn't support case-sensitive LIKE statements; contains acts like icontains for SQLite. See thedatabase note for more

information.

icontains

Case-insensitive containment test.

Example:

Entry.objects.get(headline__icontains='Lennon')

SQL equivalent:

SELECT ... WHERE headline ILIKE '%Lennon%';

SQLite users

When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons.

in

In a given list.

Example:

Entry.objects.filter(id__in=[1, 3, 4])

SQL equivalent:

SELECT ... WHERE id IN (1, 3, 4);

You can also use a queryset to dynamically evaluate the list of values instead of providing a list of literal values:

inner_qs = Blog.objects.filter(name__contains='Cheddar')

Page 27: Django - basics

entries = Entry.objects.filter(blog__in=inner_qs)

This queryset will be evaluated as subselect statement:

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

The above code fragment could also be written as follows:

inner_q = Blog.objects.filter(name__contains='Cheddar').values('pk').query

entries = Entry.objects.filter(blog__in=inner_q)

This second form is a bit less readable and unnatural to write, since it accesses the internal query attribute and requires aValuesQuerySet.

If your code doesn't require compatibility with Django 1.0, use the first form, passing in a queryset directly.

If you pass in a ValuesQuerySet or ValuesListQuerySet (the result of calling values() or values_list() on a queryset) as the

value to an __in lookup, you need to ensure you are only extracting one field in the result. For example, this will work (filtering on the blog

names):

inner_qs = Blog.objects.filter(name__contains='Ch').values('name')

entries = Entry.objects.filter(blog__name__in=inner_qs)

This example will raise an exception, since the inner query is trying to extract two field values, where only one is expected:

# Bad code! Will raise a TypeError.

inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')

entries = Entry.objects.filter(blog__name__in=inner_qs)

Warning

Page 28: Django - basics

This query attribute should be considered an opaque internal attribute. It's fine to use it like above, but its API may change between Django

versions.

Performance considerations

Be cautious about using nested queries and understand your database server's performance characteristics (if in doubt, benchmark!). Some

database backends, most notably MySQL, don't optimize nested queries very well. It is more efficient, in those cases, to extract a list of

values and then pass that into the second query. That is, execute two queries instead of one:

values = Blog.objects.filter(

name__contains='Cheddar').values_list('pk', flat=True)

entries = Entry.objects.filter(blog__in=list(values))

Note the list() call around the Blog QuerySet to force execution of the first query. Without it, a nested query would be executed,

because QuerySets are lazy.

gt

Greater than.

Example:

Entry.objects.filter(id__gt=4)

SQL equivalent:

SELECT ... WHERE id > 4;

gte

Greater than or equal to.

Page 29: Django - basics

lt

Less than.

lte

Less than or equal to.

startswith

Case-sensitive starts-with.

Example:

Entry.objects.filter(headline__startswith='Will')

SQL equivalent:

SELECT ... WHERE headline LIKE 'Will%';

SQLite doesn't support case-sensitive LIKE statements; startswith acts like istartswith for SQLite.

istartswith

Case-insensitive starts-with.

Example:

Entry.objects.filter(headline__istartswith='will')

SQL equivalent:

SELECT ... WHERE headline ILIKE 'Will%';

SQLite users

Page 30: Django - basics

When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons.

endswith

Case-sensitive ends-with.

Example:

Entry.objects.filter(headline__endswith='cats')

SQL equivalent:

SELECT ... WHERE headline LIKE '%cats';

SQLite users

SQLite doesn't support case-sensitive LIKE statements; endswith acts like iendswith for SQLite. Refer to thedatabase note documentation

for more.

iendswith

Case-insensitive ends-with.

Example:

Entry.objects.filter(headline__iendswith='will')

SQL equivalent:

SELECT ... WHERE headline ILIKE '%will'

SQLite users

When using the SQLite backend and Unicode (non-ASCII) strings, bear in mind the database note about string comparisons.

Page 31: Django - basics

range

Range test (inclusive).

Example:

start_date = datetime.date(2005, 1, 1)

end_date = datetime.date(2005, 3, 31)

Entry.objects.filter(pub_date__range=(start_date, end_date))

SQL equivalent:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

You can use range anywhere you can use BETWEEN in SQL — for dates, numbers and even characters.

year

For date/datetime fields, exact year match. Takes a four-digit year.

Example:

Entry.objects.filter(pub_date__year=2005)

SQL equivalent:

SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31 23:59:59.999999';

(The exact SQL syntax varies for each database engine.)

month

Page 32: Django - basics

For date and datetime fields, an exact month match. Takes an integer 1 (January) through 12 (December).

Example:

Entry.objects.filter(pub_date__month=12)

SQL equivalent:

SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';

(The exact SQL syntax varies for each database engine.)

day

For date and datetime fields, an exact day match.

Example:

Entry.objects.filter(pub_date__day=3)

SQL equivalent:

SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';

(The exact SQL syntax varies for each database engine.)

Note this will match any record with a pub_date on the third day of the month, such as January 3, July 3, etc.

week_day

For date and datetime fields, a 'day of the week' match.

Takes an integer value representing the day of week from 1 (Sunday) to 7 (Saturday).

Example:

Page 33: Django - basics

Entry.objects.filter(pub_date__week_day=2)

(No equivalent SQL code fragment is included for this lookup because implementation of the relevant query varies among different database

engines.)

Note this will match any record with a pub_date that falls on a Monday (day 2 of the week), regardless of the month or year in which it

occurs. Week days are indexed with day 1 being Sunday and day 7 being Saturday.

isnull

Takes either True or False, which correspond to SQL queries of IS NULL and IS NOT NULL, respectively.

Example:

Entry.objects.filter(pub_date__isnull=True)

SQL equivalent:

SELECT ... WHERE pub_date IS NULL;

search

A boolean full-text search, taking advantage of full-text indexing. This is like contains but is significantly faster due to full-text indexing.

Example:

Entry.objects.filter(headline__search="+Django -jazz Python")

SQL equivalent:

SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);

Page 34: Django - basics

Note this is only available in MySQL and requires direct manipulation of the database to add the full-text index. By default Django uses

BOOLEAN MODE for full text searches. See the MySQL documentation for additional details.

regex

Case-sensitive regular expression match.

The regular expression syntax is that of the database backend in use. In the case of SQLite, which has no built in regular expression support,

this feature is provided by a (Python) user-defined REGEXP function, and the regular expression syntax is therefore that of Python's re module.

Example:

Entry.objects.get(title__regex=r'^(An?|The) +')

SQL equivalents:

SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'c'); -- Oracle

SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite

Using raw strings (e.g., r'foo' instead of 'foo') for passing in the regular expression syntax is recommended.

iregex

Page 35: Django - basics

Case-insensitive regular expression match.

Example:

Entry.objects.get(title__iregex=r'^(an?|the) +')

SQL equivalents:

SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle

SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite

Performing raw queries New in Django 1.2: Please, see the release notes

The raw() manager method can be used to perform raw SQL queries that return model instances:

Manager.raw(raw_query, params=None, translations=None)

This method method takes a raw SQL query, executes it, and returns a RawQuerySet instance. This RawQuerySet instance can be iterated

over just like an normal QuerySet to provide object instances.

Page 36: Django - basics

This is best illustrated with an example. Suppose you’ve got the following model:

class Person(models.Model):

first_name = models.CharField(...)

last_name = models.CharField(...)

birth_date = models.DateField(...)

You could then execute custom SQL like so:

>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):

... print p

John Smith

Jane Jones

Of course, this example isn't very exciting -- it's exactly the same as running Person.objects.all(). However, raw() has a bunch of

other options that make it very powerful.

Model table names

Where'd the name of the Person table come from in that example?

By default, Django figures out a database table name by joining the model's "app label" -- the name you used inmanage.py startapp -- to

the model's class name, with an underscore between them. In the example we've assumed that the Person model lives in an app

named myapp, so its table would be myapp_person.

For more details check out the documentation for the db_table option, which also lets you manually set the database table name.

Warning

Page 37: Django - basics

No checking is done on the SQL statement that is passed in to .raw(). Django expects that the statement will return a set of rows from the

database, but does nothing to enforce that. If the query does not return rows, a (possibly cryptic) error will result.

Mapping query fields to model fields

raw() automatically maps fields in the query to fields on the model.

The order of fields in your query doesn't matter. In other words, both of the following queries work identically:

>>> Person.objects.raw('SELECT id, first_name, last_name, birth_date FROM myapp_person')

...

>>> Person.objects.raw('SELECT last_name, birth_date, first_name, id FROM myapp_person')

...

Matching is done by name. This means that you can use SQL's AS clauses to map fields in the query to model fields. So if you had some other

table that had Person data in it, you could easily map it into Person instances:

>>> Person.objects.raw('''SELECT first AS first_name,

... last AS last_name,

... bd AS birth_date,

... pk as id,

... FROM some_other_table''')

As long as the names match, the model instances will be created correctly.

Page 38: Django - basics

Alternatively, you can map fields in the query to model fields using the translations argument to raw(). This is a dictionary mapping

names of fields in the query to names of fields on the model. For example, the above query could also be written:

>>> name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}

>>> Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)

Index lookups

raw() supports indexing, so if you need only the first result you can write:

>>> first_person = Person.objects.raw('SELECT * from myapp_person')[0]

However, the indexing and slicing are not performed at the database level. If you have a big amount of Person objects in your database, it is

more efficient to limit the query at the SQL level:

>>> first_person = Person.objects.raw('SELECT * from myapp_person LIMIT 1')[0]

Deferring model fields

Fields may also be left out:

>>> people = Person.objects.raw('SELECT id, first_name FROM myapp_person')

The Person objects returned by this query will be deferred model instances (see defer()). This means that the fields that are omitted from

the query will be loaded on demand. For example:

>>> for p in Person.objects.raw('SELECT id, first_name FROM myapp_person'):

... print p.first_name, # This will be retrieved by the original query

Page 39: Django - basics

... print p.last_name # This will be retrieved on demand

...

John Smith

Jane Jones

From outward appearances, this looks like the query has retrieved both the first name and last name. However, this example actually issued

3 queries. Only the first names were retrieved by the raw() query -- the last names were both retrieved on demand when they were printed.

There is only one field that you can't leave out - the primary key field. Django uses the primary key to identify model instances, so it must always be included in a raw query. An InvalidQuery exception will be raised if you forget to include the primary key.

Adding annotations

You can also execute queries containing fields that aren't defined on the model. For example, we could use PostgreSQL's age() function to get

a list of people with their ages calculated by the database:

>>> people = Person.objects.raw('SELECT *, age(birth_date) AS age FROM myapp_person')

>>> for p in people:

... print "%s is %s." % (p.first_name, p.age)

John is 37.

Jane is 42.

...

Passing parameters into raw()

Page 40: Django - basics

If you need to perform parameterized queries, you can use the params argument to raw():

>>> lname = 'Doe'

>>> Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname])

params is a list of parameters. You'll use %s placeholders in the query string (regardless of your database engine); they'll be replaced with

parameters from the params list.

Warning

Do not use string formatting on raw queries!

It's tempting to write the above query as:

>>> query = 'SELECT * FROM myapp_person WHERE last_name = %s' % lname

>>> Person.objects.raw(query)

Don't.

Using the params list completely protects you from SQL injection attacks, a common exploit where attackers inject arbitrary SQL into your

database. If you use string interpolation, sooner or later you'll fall victim to SQL injection. As long as you remember to always use the params list you'll be protected.

Page 41: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

1 | P a g e

SESSION 4 – URL Configuration and HttpRequest/HttpResponse

URL Configuration URLConf is a module that maps between URL patterns to Python view functions. Regularly, you define

URL patterns in urls.py of a Project or each App.

Example of URL patterns

You should know:

- In Python, r’’ is a raw string. It denotes that this string should not be escaped.

- The URL patterns are in Regex format. You can reference at

http://docs.python.org/library/re.html, however, you should not focus on it now.

- Caret sign (^) denotes the beginning of a pattern.

- Dollar sign ($) denotes the end of a pattern. This is the reason that when including URL patterns

of an App, you do not put $ at the end because it still continues to match:

- ?P<param_name> is to define named group. After matching, the URL parameter will be passed

to view function’s parameter:

The view’s parameter MUST be the same with the URL parameter, e.g. movie_id.

- \d+ is to match a string (continuous characters) which contains digits only, i.e. 0,1,2… 9

Some useful patterns The following patterns are used in almost usual cases. You can find more patterns from the Internet

(Python Regex) or master Regex to create on your own.

Page 42: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

2 | P a g e

- \d{n}: n is an integer number which indicates how many characters in this digit string. For

example, \d{4} will match 0123 but not match 123.

- \d+: a digit string with no limit characters.

- \w{n} and \w+: the same but matches strings with alphabetical and digit and underscore

characters.

- \[a-z]{n} and \[a-z]+: accepts a-z characters only.

- \[a-zA-Z0-9]+: like what you think of :D.

- [-\w\d]{36}: matches for uuid.uuid1.

url() function

Use this wrapper function if you want to define name for an URL. You can use this name in template files

through url template tag like the following example:

You can also pass URL parameters in url template tag (Hint: used to construct links for exploring a movie

in the example). See the documentation for more details.

include() function You have used it already so I do not need to explain it again ^^.

HttpRequest and HttpResponse When the client requests to Web server at the URL, it will pass the request parameter to the

corresponding view function. This parameter is HttpRequest response.

Each view function has to return an HttpResponse object. Django will use the object to return the client

HTML (or other formats).

The documentation is clear and informative enough. The following points are what you should to focus:

Page 43: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

3 | P a g e

HttpRequest: https://docs.djangoproject.com/en/1.3/ref/request-response/

method, GET, POST, user, raw_post_data, read().

HttpResponse: https://docs.djangoproject.com/en/1.3/ref/request-response/

write(),HttpResponse subclasses.

Shortcuts: https://docs.djangoproject.com/en/1.3/topics/http/shortcuts/

render_to_response, render_to_string, redirect.

Exercises 1. Reconstruct the URL patterns of your Session 3 exercises. You have to use URL parameters to

shorten your patterns.

2. Feature: Add new movie by submitting an XML file (write a small page for submitting file)

For director, actor and category, if name does not exist, it will create a new row in database.

Otherwise, it will find the existing row to assign to the movie object.

Hint: Read the first example of File Uploading; use ElementTree lib to parse XML file

(http://effbot.org/zone/element.htm).

Requirement Submit your answers for exercise 1 before 12:00 PM on Friday, September 30th, 2011 at

[email protected]

Submit your answers for exercise 2 before 00:00 AM on Monday, October 3rd, 2011 at

[email protected]

Page 44: Django - basics

Session6:DjangoTemplateSystem

Review class: read

• File Upload: Overview | File Objects | Managing File

• Generic views: Overview | Built-in generic views

• CSS: coi het den phan CSS Advanced Align

Learning

Variable: {{student.name}} {{student.get_average 1 2}} #1, 2 tham so truyen vao

Filter: -> co cac built in ngoai ra co the viet them vao

Student.name | upper

aBC ABC

cac ham thuong dung: upper

lower

truncate_word

escape -> mac dinh se escape het

length

Tag: -> co cac built in ngoai ra co the viet them vao

if

if else

if equal

for

Page 45: Django - basics

comment {# #}

Inheritance Base.html

<div> {% block content%}

{%endblock content%} </div>

Movie.html

<div> {% extends block %} </div> #first template in child template

{% block content of the movie.html (specific) %}

Other: user {{block.super}}

Other: Python manag.py dumpdata > data.json # xuat data ra file

loaddata < data.json #nhap data tu file

flush #xoa data hoan toan

Muon luu cac file tinh nhu: image, css,… trong STATIC_ROOT trong setting.py

Exercise: Redesign the movie website look like this:

MOVIE DATABASE

MOVIES DIRECTOR ACTOR CATEGORY

COPYRIGHT

Page 46: Django - basics

Tab: dung

<ul style = “display:inline”>

<li>Movie </li>

</ul>

Page 47: Django - basics

SESSION 8: FORM

Overview: 1. If form is huge: you can make new file forms.py to store them

Else: include it in models.py

Lookup more built-in field form: https://docs.djangoproject.com/en/1.3//ref/forms/fields/

2. Using form in a view:

3. Processing data with Form:

4. Displaying a form using a template:

form.as_p will output the form with each form field and accompanying label wrapped in a

paragraph. Here's the output for our example template:

Page 48: Django - basics

You can also use form.as_table to output table rows (you'll need to provide your

own <table> tags) and form.as_ul to output list items.

ModelForm 1. Syntax:

2. Model field and model form equivalent:

3. Other works just as normal form: but instead of processing with form.cleaned_data, just use

f.save() for short

4. Notices:

a. Using subsets of field in the form:

Page 49: Django - basics

1. Use the fields attribute of the ModelForm's inner Meta class. This attribute, if

given, should be a list of field names to include in the form. The order in which

the fields names are specified in that list is respected when the form renders

them. 2. Use the exclude attribute of the ModelForm's inner Meta class. This attribute, if

given, should be a list of field names to exclude from the form.

b. Overriding default fields or widget:

c. Changing order of fields:

d. Form inheritance:

Homework:

Chuyen het sang form cho movie, director, actor ve add, edit

Page 50: Django - basics

THEORY

1. Understand User model.

There are many fields in this model but you need to focus on 3 ones: username (unique), email (unique,

optional) and password (hashed).

Django does not store raw password, which you enter to login, but hashed string of the password. When

users submit their password, it will also be hashed and matched with the hashed password in database.

This mechanism ensures that no one can get password of users when controlling access to database. As

you know, many people use the same password with many different accounts so this is absolutely useful.

To create a User instance, you should use User.objects.create_user(username, password, email).

Parameter ``password`` in this function is the raw password. If you use User(username, password,

email), the password you have to pass is the hashed one, very disturbing.

To set/check password, similarly you should use its utility functions instead of assigning

directly: set_password(password),check_password(password).

2. How to use User in view

There are 3 utility functions in django.contrib.auth:

authenticate(username, password)

login(request, user)

logout(request)

authenticate() is for checking username and password matching. If username does not exist or password

does not match, it will return None. Otherwise, it returns a User instance corresponding to who you want

to check. login() and logout() is easy to understand.

I explain a bit about Django authentication system. login() function will append to request a HTTP

COOKIE parameter session_id. This session_id will be used to identify which user is working with the

Web server (because HTTP is stateless). Each HTTP request will send session_id belong. You can

watch session_id (COOKIE) by using Firebug on Firefox or Developer Tools on Chrome.

There are 2 ways to force that only logged-in user can access the view:

RAW WAY

def view(request);

if request.user.is_authenticated():

pass # do something

else:

pass # return an error view or redirect to login view, for example

DECORATOR

@login_required()

def view(request):

pass

When using decorator, if the user has not logged in yet, it will be redirected to login page (LOGIN_URL in

settings.py, default is /account/login/)

Page 51: Django - basics

3. Extending User information

You can extend the information fields for a user such as date of birth, address, habits, etc. by using

Authentication Profile. There are 3 steps:

- Declare in settings.py: AUTH_PROFILE_MODULES = 'accounts.UserProfile'

+ accounts is an example app

+ UserProfile (you can name it whatever you want) is your own Model class. For example:

class UserProfile(models.Model):

user = models.ForeignKey(User, unique=True) # this is compulsory

# additional information

dob = models.DateField()

# ... many as you wish

User.profile = property(lambda u: PubProfile.objects.get_or_create(user=u)[0]) # (Tips)

Then you can access UserProfile instance by calling the instance method of User model: get_profile()

(Tips): This line is optional but extremely useful. You can access UserProfile just like a field in a Model

instance. For example: user.profile.dob = datetime.date.today() instead of user.get_profile().dob =

datetime.date.today(). Moreover, you need to understand that when calling get_profile() or profile

(property), it will query from SQL database. You should care about overhead:

profile = user.get_profile() # 1 query

profile.dob = datetime.date.today()

profile.address = 'abc'

----> COST 1 QUERY

Instead of:

user.get_profile().dob = datetime.date.today() # 1 query

user.get_profile().address = 'abc' # 1 query

----> COST 2 QUERIES

4. Email Sending tips

https://docs.djangoproject.com/en/1.3/topics/email/

( Do research by yourself first before reading this tip)

a. Testing on localhost:

- In settings.py:

EMAIL_HOST = 'localhost'

EMAIL_PORT = 1025

- Open a command-line: python -m smtpd -n -c DebuggingServer localhost:1025

b. Sending email with your Gmail account

- In settings.py:

EMAIL_HOST = 'smtp.gmail.com'

EMAIL_HOST_USER = '[email protected]'

EMAIL_HOST_PASSWORD = 'yourpass'

EMAIL_PORT = 587 # Check on the Internet if not successful

EMAIL_USER_TLS = True # Gmail now accepts HTTPS only

Page 52: Django - basics

EXERCISES

1. Create register/login page with additional information (DOB, Habits, Address, Country, etc.) for Movie

Database. Only registered user can access it.

2. Do research about Email Sending to implement this feature: Send a list of Actors or Directors or Movies

to user's email.

Lam viec truc tiep tren template (co built in san) va views thoi ( nho import vao)

Flow (ve hinh)> thiet ke app > URLs (nen viet ro) > model > views > template

(static nen de ngoai project thu muc luon)

Page 53: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

1 | P a g e

SESSION 10 – The Admin Site

Setup the Admin Site Django framework comes up with its auto-generated CMS (Content Management System). It is

extremely useful and help us to reduce development time.

To use the Admin Site, you need to do the following steps:

1. Uncomment ‘django.contrib.admin’ in INSTALLED_APPS (settings.py).

2. Make sure that django.contrib.auth, django.contrib.contenttypes, django.contrib.messages

and django.contrib.sessions is installed. Those are its dependencies.

3. Uncomment admin pattern in urls.py.

admin.autodiscover() function will traverse all app directories to find each admin.py file

(optional for an app). You will be learnt what to declare in admin.py in the next section.

4. Finally, you need to sync the database again to install admin app.

5. Start the server and go to the Admin Site at http://127.0.0.1:8000/admin/. Login with your

super user account which is recommended to create when syncing database at the first time. If

you haven’t created super user account yet, you can do it by using manage.py shell.

Page 54: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

2 | P a g e

With the default Admin Site, you can modify Users, Groups and Sites model instances. Add new

Users and Groups by yourself to examine features of the Admin Site.

Add new Model to the Admin Site Just like Users or Groups model, you can add your own Models to be managed by the Admin Site:

1. Create admin.py file inside your app folder which contains Models (in models.py) you want to

register with the Admin Site.

2. Register a Model by using admin.site.register(YourModel). This is a quick way to do that, for

more advance settings see the next section.

3. Login into the Admin Site again to see the changes.

Page 55: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

3 | P a g e

Customize Interface You can customize the interface of the Admin Site by declaring your own ModelAdmin objects. Let’s

examine the following example:

1. If registering Model with default options, the interface of Adding page is like below:

2. I want to divide the information into 2 different groups: Basic Information and Advanced

Information.

Page 56: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

4 | P a g e

3. This is the code to achieve the new interface:

For more options of ModelAdmin, please reference at

https://docs.djangoproject.com/en/1.3/ref/contrib/admin/#modeladmin-objects

Page 57: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

5 | P a g e

Admin Actions In some cases, you need to achieve more complicated actions than only add/remove/change Model

instances. It is when you want to write Admin Actions. For example, you want a feature that change all

selected Movies to 21 recommended age viewer:

1. First, write your Action function in ModelAdmin subclass

your_action(self, request, queryset)

queryset is selected instances and request is HttpRequest (same with view function).

2. Declare attribute actions of ModelAdmin

actions = [‘your_action’]

3. This is the total code

4. Go to the Admin Site and examine the changes

After selecting instances and action, you need to click Go button to process it.

Page 58: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

1 | P a g e

SESSION 11 – Deployment

In order to deploy your Django website, you need to install and setup the following packages:

- Python 2.x

- Django 1.2.x

- Apache2 and lib mod_wsgi

Environment: Ubuntu 10.10

Install python > sudo apt-get install python python-dev python-setuptools build-essential

Install pip > sudo easy_install –U pip

Install Django > sudo pip install Django

Install Apache2 and mod_wsgi > sudo apt-get install apache2 libapache2-mod-wsgi

Test mod_wsgi

Write WSGI Script > sudo mkdir /srv/www

> sudo mkdir /srv/www/wsgi

> sudo nano /srv/www/wsgi/app.wsgi

Page 59: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

2 | P a g e

Write Apache Configuration Script > sudo nano /etc/apache2/sites-available/test

Enable site: > sudo a2ensite test

Reload apache2 service: > sudo service apache2 reload

Config host name This is for testing purpose on local only. In practice, you need to configure DNS settings for your own

domain (you will need to purchase one, e.g. epsilon-mobile.com)

> sudo nano /etc/hosts

Prepend this line in hosts file: 127.0.1.1 wsgi.djangoserver

The reason for this setting is, when you go to http://wsgi.djangoserver in Web browser, the request will be resolved at 127.0.1.1 (localhost) and match with VirtualHost configuration.

TESTING DJANGO > cd /srv/www/

> sudo django-admin.py startproject hello

> sudo mkdir /srv/www/hello/apache

> sudo nano /srv/www/hello/apache/django.wsgi

Page 60: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

3 | P a g e

Your Apache configuration script is like below:

After done, test your deployed site at http://hello.djangoserver/

TIP 1: If we modify the code in Django project then rather than restarting apache we can just touch the wsgi file and the changes will be picked up:

> sudo touch /srv/www/hello/apache/django.wsgi

TIP 2: Even when your website has been deployed, you still can test in development mode:

> python manage.py runserver 0:8080

It will have the same effect with the deployed site if you use the same settings.py, more exactly point to

the same database. Access the development site at http://hello.djangoserver:8080/

In-class Exercises 1. Deploy your Movie Database website so that everyone who joins the Wi-fi network

epsilon_mobile can access it.

Page 61: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

4 | P a g e

Go to the Admin Site of your website in deployment mode. Does it display correctly with

image/css/javascript? If not, try to fix it by yourself (Hint: Google).

2. Deploy your site with nginx server. Nginx is a light-weight FastCGI-support Web server, it is most

effective when being used to serve static files.

Reference: http://www.dmclaughlin.com/2008/11/03/complete-guide-to-deploying-django-on-

ubuntu-with-nginx-fastcgi-and-mysql/

(You only need to read from Installing nginx)

Reminder Your final project should be presented at the deployment mode. The reason is that you might face some

troubles to make it run smoothly in practice. This is a good experience.

Page 62: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

1 | P a g e

Final Assignment

Instruction To confirm your effective learning, you are required to complete a final assignment to experience all

knowledge and techniques taught at this course. You are provided 2 topics, however, you can also

create your own ideas, then, submit them to our instructors to approve. Instructors take a responsibility

to ensure that your own topic matches what you need to achieve after this course.

You need to submit your code by 00:00 AM on October 17th, 2011.

The presentation of your assignment will be hold at 07:00 PM on October 19th, 2011.

TOPIC 1: Social Network

User Story As a user, I can register my account at the Website. After registering, I can sign in to my homepage. At

my homepage, I prefer to share my own ideas, pictures of my fantastic trips to all my friends. Ah, about

friends, I can make friends with anyone who has an account, hence, inviting friends by email is what I

will try to do.

Requirement You need to complete the following features:

- Register an account

- Change account information

- Add/Remove friends (relationship)

- Show a homepage with the latest sharing from user’s friends (login-required)

- Post a sharing which can be in texts and pictures

- Invite friends to join the network by email

TOPIC 2: Comic Online Store

User Story I need to have an account to read comics. There are many comic series and each one contains multiple

issues. To access an issue, I have to purchase it or subscribe the series that this issue belongs to. When

reading an issue, I can move between pages, zoom a page and bookmark page so that I can revisit for

next reading.

Requirement You need to complete the following features:

Page 63: Django - basics

Python/Django Course 2011 Epsilon Mobile Pte. Ltd.

2 | P a g e

- Register a Reader account

- Show a Comic Series page which contains a list of issues

- Manage (Add/Remove/Change) Comic Series, Comic Issues, etc. (Admin page)

- Purchase an issue (e.g. 0.99$, 1.99$, etc.)

- Subscribe a series (e.g. 99$)

- Read a comic issue: Move between comic pages, zoom a page

- Bookmark page is a plus

DUCMINHKHOI
Note
dung cookie de luu trang hien tai request.cookie...
DUCMINHKHOI
Note
is_staff decorator