from django.http import HttpResponse
import datetime
def current_datetime(request):
now = datetime.datetime.now()
html = '<html><vody>It is now %s.</body></html>' % now
return HttpResponse(html)
return HttpResponseNotFound('<h1>Page not found</h1>')
!pip install -U django==1.7
Requirement already up-to-date: django==1.7 in /Users/re4lfl0w/.virtualenvs/general/lib/python2.7/site-packages Cleaning up...
!pip freeze | grep Django
Django==1.7
!pwd
/Users/re4lfl0w/Documents/ipython/books/django_python_web_programming
!django-admin.py startproject mysite
!ls -l
total 104 -rw-r--r-- 1 re4lfl0w staff 41364 4 16 00:34 ch02.ipynb -rw-r--r-- 1 re4lfl0w staff 6627 4 16 01:13 ch03.ipynb drwxr-xr-x 3 re4lfl0w staff 102 4 15 23:33 ch1 drwxr-xr-x 9 re4lfl0w staff 306 4 15 23:33 ch2 drwxr-xr-x 7 re4lfl0w staff 238 4 15 23:33 ch3-4 drwxr-xr-x 7 re4lfl0w staff 238 4 15 23:33 ch3-6 drwxr-xr-x 7 re4lfl0w staff 238 4 15 23:33 ch3-7 drwxr-xr-x 7 re4lfl0w staff 238 4 15 23:33 ch4 drwxr-xr-x 9 re4lfl0w staff 306 4 15 23:33 ch5-1 drwxr-xr-x 9 re4lfl0w staff 306 4 15 23:33 ch5-2 drwxr-xr-x 10 re4lfl0w staff 340 4 15 23:33 ch5-3 drwxr-xr-x 12 re4lfl0w staff 408 4 15 23:33 ch6-4 drwxr-xr-x 12 re4lfl0w staff 408 4 15 23:33 ch6-5 drwxr-xr-x 4 re4lfl0w staff 136 4 16 01:19 mysite
!ls -l mysite
total 8 -rwxr-xr-x 1 re4lfl0w staff 249 4 16 01:19 manage.py drwxr-xr-x 6 re4lfl0w staff 204 4 16 01:19 mysite
!ls -l mysite/mysite/
total 24 -rw-r--r-- 1 re4lfl0w staff 0 4 16 01:19 __init__.py -rw-r--r-- 1 re4lfl0w staff 1972 4 16 01:19 settings.py -rw-r--r-- 1 re4lfl0w staff 297 4 16 01:19 urls.py -rw-r--r-- 1 re4lfl0w staff 387 4 16 01:19 wsgi.py
!mv mysite/ ch3
!ls -l
total 112 -rw-r--r-- 1 re4lfl0w staff 41364 4 16 00:34 ch02.ipynb -rw-r--r-- 1 re4lfl0w staff 9968 4 16 01:20 ch03.ipynb drwxr-xr-x 3 re4lfl0w staff 102 4 15 23:33 ch1 drwxr-xr-x 9 re4lfl0w staff 306 4 15 23:33 ch2 drwxr-xr-x 4 re4lfl0w staff 136 4 16 01:19 ch3 drwxr-xr-x 7 re4lfl0w staff 238 4 15 23:33 ch3-4 drwxr-xr-x 7 re4lfl0w staff 238 4 15 23:33 ch3-6 drwxr-xr-x 7 re4lfl0w staff 238 4 15 23:33 ch3-7 drwxr-xr-x 7 re4lfl0w staff 238 4 15 23:33 ch4 drwxr-xr-x 9 re4lfl0w staff 306 4 15 23:33 ch5-1 drwxr-xr-x 9 re4lfl0w staff 306 4 15 23:33 ch5-2 drwxr-xr-x 10 re4lfl0w staff 340 4 15 23:33 ch5-3 drwxr-xr-x 12 re4lfl0w staff 408 4 15 23:33 ch6-4 drwxr-xr-x 12 re4lfl0w staff 408 4 15 23:33 ch6-5
%cd ch3
/Users/re4lfl0w/Documents/ipython/books/django_python_web_programming/ch3
!ls -l
total 8 -rwxr-xr-x 1 re4lfl0w staff 249 4 16 01:19 manage.py drwxr-xr-x 6 re4lfl0w staff 204 4 16 01:19 mysite
!python manage.py startapp polls
!tree
. ├── manage.py ├── mysite │ ├── __init__.py │ ├── __init__.pyc │ ├── settings.py │ ├── settings.pyc │ ├── urls.py │ └── wsgi.py └── polls ├── __init__.py ├── admin.py ├── models.py ├── tests.py └── views.py 2 directories, 12 files
!python manage.py migrate
Operations to perform: Apply all migrations: admin, contenttypes, auth, sessions Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying sessions.0001_initial... OK
!echo 'db.sqlite3' > .gitignore
!cat .gitignore
db.sqlite3
!git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
nothing added to commit but untracked files present (use "git add" to track)
!git add .
!git commit -m "Add .gitignore"
[master 2a59fca] Add .gitignore 1 file changed, 1 insertion(+) create mode 100644 .gitignore
!git status
On branch master nothing to commit, working directory clean
!python manage.py runserver 0.0.0.0:8002
Performing system checks... System check identified no issues (0 silenced). April 15, 2015 - 16:44:48 Django version 1.7, using settings 'mysite.settings' Starting development server at http://0.0.0.0:8002/ Quit the server with CONTROL-C. [15/Apr/2015 16:44:49] "GET /admin/ HTTP/1.1" 200 2880 [15/Apr/2015 16:44:49] "GET /static/admin/css/base.css HTTP/1.1" 304 0 [15/Apr/2015 16:44:49] "GET /static/admin/css/dashboard.css HTTP/1.1" 304 0 ^C
# 상호작용이라 쉘에서 실행해야 됨
#!python manage.py createsuperuser
# 프로젝트 뼈대를 만든 후 디렉토리 모습
!tree
. ├── db.sqlite3 ├── manage.py ├── mysite │ ├── __init__.py │ ├── __init__.pyc │ ├── settings.py │ ├── settings.pyc │ ├── urls.py │ ├── urls.pyc │ ├── wsgi.py │ └── wsgi.pyc └── polls ├── __init__.py ├── admin.py ├── models.py ├── tests.py └── views.py 2 directories, 15 files
컬럼명 | 타입 | 제약 조건 | 설명 |
---|---|---|---|
id | integer | NotNull, PK, AuthIncrement | Primary Key |
question_text | varchar(200) | NotNull | 질문 문장 |
pub_date | datetime | NotNull | 질문 생성 시각 |
컬럼명 | 타입 | 제약 조건 | 설명 |
---|---|---|---|
id | integer | NotNull, PK, AutoIncrement | Primary Key |
choice_text | varchar(200) | NotNull | 답변 항목 문구 |
votes | integer | NotNull | 투표 카운트 |
question_id | integer | NotNull, FK(Question.id), Index | Foreign Key |
!git log
commit b30c3498dde87aa58aa6dbb91dce1b5972465664 Author: re4lfl0w <[email protected]> Date: Thu Apr 16 01:58:21 2015 +0900 Add polls application and change TIME_ZONE Asia/Seoul commit 2a59fca629165c6474c346e4b2469357984f63f6 Author: re4lfl0w <[email protected]> Date: Thu Apr 16 01:36:20 2015 +0900 Add .gitignore commit 196a794a8196535ff334cc063be192f480501cdd Author: re4lfl0w <[email protected]> Date: Thu Apr 16 01:25:55 2015 +0900 Add python manage.py startapp polls commit aca47393f534ff7a8c0638cb8390ccdc32a397a2 Author: re4lfl0w <[email protected]> Date: Thu Apr 16 01:23:45 2015 +0900 Initialize. startproject mysite
테이블 컬럼명 | 컬럼 타입 | 장고의 클래스 변수 | 장고의 필드 클래스 |
---|---|---|---|
id | integer | (question_id) | (PK는 장고에서 자동 생성해줌) |
question_text | varchar(200) | question_text | models.CharField(max_length=200) |
pub_date | datetime | pub_date | models.DateTimeField('date published') |
컬럼명 | 타입 | 장고의 클래스 변수 | 장고의 필드 클래스 |
---|---|---|---|
id | integer | (choice_id) | (PK는 장고에서 자동 생성해줌) |
choice_text | varchar(200) | choice_text | models.ForeignKey(Question) |
votes | integer | votes | models.CharField(max_length=200) |
question_id | integer | question_id | models.IntegerField(default=0) |
!git status
On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: polls/admin.py modified: polls/models.py no changes added to commit (use "git add" and/or "git commit -a")
!git add .
!git commit -m "Add Question and Choice model"
[master 47cc44b] Add Question and Choice model 2 files changed, 19 insertions(+), 2 deletions(-)
!python manage.py makemigrations
No changes detected
!python manage.py migrate
Operations to perform: Synchronize unmigrated apps: polls Apply all migrations: admin, contenttypes, auth, sessions Synchronizing apps without migrations: Creating tables... Installing custom SQL... Installing indexes... Running migrations: No migrations to apply.
$ python manage.py sqlmigrate polls 0001
!python manage.py sqlmigrate polls 0001
CommandError: App 'polls' does not have migrations
URL 패턴 | 뷰 이름 | 뷰가 처리하느 ㄴ내용 |
---|---|---|
/polls/ | index() | index.html 템플릿을 보여줌 |
/polls/5/ | detail() | detail.html 템플릿을 보여줌 |
/polls/5/vote/ | vote() | detail.html에 있는 폼을 POST 방식으로 처리 |
/polls/5/results/ | results() | results.html 템플릿을 보여줌 |
/admin/ | (장고 기능) | Admin 사이트를 보여줌(장고에서 기본으로 제공함) |
url(regex, view, kwargs=None, name=None, prefix='')
화면에 질문을 보여주는 로직을 구현하기 위해 뷰 함수와 템플릿 파일을 코딩하는 것
뷰 함수와 템플릿음 서로에게 영향을 미치기 때문에 보통 같이 작업하게 됨
또한, UI 화면을 생각하면서 코딩하게 되므로 일반적으로 템플릿을 먼저 코딩하는 것이 정석
여기서 중요한 점: 뷰 함수에서 어떤 파라미터를 템플릿으로 넘겨줄지 결정하는 것
우리 예제에서는 질문으로 사용될 여러개의 question_text를 화면에 보여줘야 하고
또한 URL 링크 연결을 위해 템플릿에서 question.id도 필요함
이 2가지 정보가 함께 들어있는 Question 객체를 넘겨주면 됨
이 사항을 index() 뷰 함수에 코딩하겠음
!tree
. ├── db.sqlite3 ├── manage.py ├── mysite │ ├── __init__.py │ ├── __init__.pyc │ ├── settings.py │ ├── settings.pyc │ ├── urls.py │ ├── urls.pyc │ ├── wsgi.py │ └── wsgi.pyc └── polls ├── __init__.py ├── __init__.pyc ├── admin.py ├── admin.pyc ├── models.py ├── models.pyc ├── templates │ └── polls │ └── index.html ├── tests.py ├── urls.py ├── urls.pyc ├── views.py └── views.pyc 4 directories, 22 files
url(r'^polls/(?P\<question_id\>\d+)/$', views.detail, name='detail'),
단축함수: 대상 객체를 리스트로 가져오는 get_list_or_404() 단축함수도 있음. get_object_or_404() 단축 함수는 get() 함수를 사용하는 데 비해, get_list_or_404() 단축함수는 filter() 함수를 사용하고 또한 리스트가 비어 있으면 Http404 Exception을 발생시킴
reverse('polls:results', args=(p.id,))
reverse() 함수를 사용하여 URL을 구하는 것은 URLconf 에 이미 정의된 URL 패턴에서 URL 스트링을 추출하는 방식이므로, 소스에 URL 스트링을 하드코딩하지 않도록 함
/polls/<question_id>/results/ -> views.results() reverse() 함수로 URL 추출 /polls/3/results/ <- reverse('polls:results', args=(3,))
{% url 'polls:detail' question.id %} # 템플릿에서 사용됨
reverse('polls:detail', args=(question_id,)) # 뷰 함수에서 사용됨