프로젝트 생성, 관리
각각의 프로젝트들은 projects
폴더 하위에 새 폴더를 만들어 사용한다. 새로 시작할 블로그 프로젝트는 projects/blog
경로를 사용한다.
$ mkdir django-tutorial
$ cd django-tutorial/
$ pwd
/django-tutorial
# 가상환경 생성
$ pyenv virtualenv 3.4.3 django_tutorial_env
# 가상환경 적용
$ pyenv local django_tutorial_env
# Django 설치
$ pip list
$ pip install django
# Django Project 생성
$ django-admin startproject mysite
# 진행상태 확인
$ l
total 8
drwxr-xr-x 4 limhm staff 136B 2 6 11:06 .
drwxr-xr-x 10 limhm staff 340B 2 6 11:04 ..
-rw-r--r-- 1 limhm staff 20B 2 6 11:05 .python-version
drwxr-xr-x 4 limhm staff 136B 2 6 11:06 mysite
$ cd ..
$ tree django-tutorial
django-tutorial
└── mysite
├── manage.py
└── mysite
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
구조 설계
(Project name) <Repository directory>
└── django_app <Django project directory>
├── manage.py
└── (Project name) <Settings Directory>
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
프로젝트명과 프로젝트를 담고 있는 폴더명(프로젝트 컨테이너 폴더)은 별개로 취급된다. Django에서 프로젝트 생성 시 기본적으로 프로젝트명과 프로젝트를 담고 있는 폴더명을 일치하게 생성해주는데, 처음에는 헷갈릴 수 있으므로 프로젝트를 담고 있는 폴더명은 다르게 바꾸어준다.
$ cd django-tutorial
$ mv mysite django_app
$ tree django-tutorial
django-tutorial
└── django_app
├── manage.py
└── mysite
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
Git 설정
$ git init
$ vi .gitignore
$ pip freeze > requirements.txt
$ pwd
/django-tutorial
$ l
total 24
drwxr-xr-x 7 limhm staff 238B 2 6 11:13 .
drwxr-xr-x 10 limhm staff 340B 2 6 11:04 ..
drwxr-xr-x 9 limhm staff 306B 2 6 11:16 .git
-rw-r--r-- 1 limhm staff 2.6K 2 6 11:13 .gitignore
-rw-r--r-- 1 limhm staff 20B 2 6 11:05 .python-version
drwxr-xr-x 4 limhm staff 136B 2 6 11:06 django_app
-rw-r--r-- 1 limhm staff 15B 2 6 11:13 requirements.txt
$ git remote add origin https://github.com/pinstinct/django_tutorial_class.git
$ py .
$ ./manage.py runserver
$ git commit -a -m "Project init"
Pycharm 단축키
go to line에 할당된 cmd + l 제거
reformat code에 cmd + l 추가
reformat code : pip 규칙에 자동으로 맞춰준다. 자주 사용하는 것이 좋다.
# .gitignore에 추가
.ieda/
Django Tutorial
$ python -m django --version
$ mkdir polls
$ l
total 32
drwxr-xr-x 6 limhm staff 204B 2 6 11:39 .
drwxr-xr-x 8 limhm staff 272B 2 6 11:38 ..
-rw-r--r-- 1 limhm staff 12K 2 6 11:29 db.sqlite3
-rwxr-xr-x 1 limhm staff 804B 2 6 11:06 manage.py
drwxr-xr-x 7 limhm staff 238B 2 6 11:29 mysite
drwxr-xr-x 2 limhm staff 68B 2 6 11:39 polls
$ python manage.py startapp polls
$ tree -I '__pycache__'
.
├── db.sqlite3
├── manage.py
├── mysite
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── polls
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
# alias tree-python 추가
# source ~/.zshrc
# pycharm open!
# Project Interpreter 설정
# usr/locar/var/pyenv/versions/django-toturial-env/bin/python
Hello world 출력
# mysite/urls.py
from django.conf.urls import url, include
urlpatterns = [
# polls/일 경우, polls.urls를 호출
url(r'^polls/', include('polls.urls')),
url(r'^admin/', admin.site.urls),
]
# polls/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
# 아무것도 입력이 되지 않았을 경우, views.index 호출
url(r'^$', views.index),
]
# polls/views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls site.")
데이터 베이스-모델
# polls/models.py
# 데이터 베이스가 어떻게 만들어질지 정의
class Qeustion(models.Model):
q_tesxt = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Qeustion)
c_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
# mysite/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# polls가 장고에서 관리된다고 알려준다.
'polls.apps.PollsConfig',
]
$ python manage.py makemigrations polls
Migrations for 'polls':
polls/migrations/0001_initial.py:
- Create model Choice
- Create model Qeustion
- Add field question to choice
# 결과를 polls/migrations/0001_initial.py에서 확인
# 실행할 sql문 확인
$ ./manage.py sqlmigrate polls 0001
BEGIN;
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL
);
--
-- Create model Question
--
CREATE TABLE "polls_question" (
"id" serial NOT NULL PRIMARY KEY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- choice에 field 필드 추가
--
# 관례상 외래키에 _id를 붙힌다.
ALTER TABLE "polls_choice" ADD COLUMN "question_id" integer NOT NULL;
ALTER TABLE "polls_choice" ALTER COLUMN "question_id" DROP DEFAULT;
CREATE INDEX "polls_choice_7aa0f6ee" ON "polls_choice" ("question_id");
ALTER TABLE "polls_choice"
ADD CONSTRAINT "polls_choice_question_id_246c99a640fbbd72_fk_polls_question_id"
FOREIGN KEY ("question_id")
REFERENCES "polls_question" ("id")
DEFERRABLE INITIALLY DEFERRED;
COMMIT;
# 데이터 베이스 생성
$ ./manage.py migrate
Applying polls.0001_initial... OK
SQL대신 장고 ORM으로 다루기
# ipython으로 실행하기 위해 설치
$ pip install ipython
$ pip install django_extensions
# mysite/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_extensions',
'polls.apps.PollsConfig',
]
$ python manage.py shell_plus
In [1]: from polls.models import Question, Choice
# Question 객체를 가진 모든 것
In [2]: q = Question.objects.all()
In [3]: q
Out[3]: <QuerySet []>
# .query : 쿼리문 확인
In [4]: print(q.query)
SELECT "polls_question"."id", "polls_question"."q_text", "polls_question"."pub_date" FROM "polls_question"
In [5]: from django.utils import timezone
In [6]: q = Question(q_text = "what new?", pub_date=timezone.now())
In [8]: q.save()
In [9]: q.id
Out[9]: 1
In [10]: q.q_text
Out[10]: "what new?"
In [11]: q.pub_date
Out[11]: datetime.datetime(2017, 2, 6, 12, 22, 38, 99032, tzinfo=<UTC>)
# 아직 메모리 상에만 있음
In [12]: q.q_text = "what up?"
# 저장을 해주면, 데이터베이스에 적용 됨
In [13]: q.save()
# filter는 where절 사용, 결과는 리스트로 반환
# 값이 없으면, 빈 리시트 반환
In [4]: print(Question.objects.filter(id=1).query)
SELECT "polls_question"."id", "polls_question"."q_text", "polls_question"."pub_date" FROM "polls_question" WHERE "polls_question"."id" = 1
# get은 한 개만 리턴
In [10]: q = Question.objects.get(pk=1)
In [14]: q
Out[14]: <Question: what up?>
In [15]: from django.utils import timezone
In [16]: current_year = timezone.now().year
# __ : 속성의 속성을 참조할 때
In [17]: Question.objects.get(pub_date__year=current_year)
Out[17]: <Question: Whats up?>
# Choice 객체 확인
# 역참조 : 역참조할테이블(소문자)_set 으로 역참조
In [18]: q.choice_set.all()
Out[18]: <QuerySet []>
# 객체 생성
In [19]: q.choice_set.create(c_text='Not much', votes=0)
Out[19]: <Choice: Not much>
In [20]: q.choice_set.create(c_text='The sky', votes=0)
Out[20]: <Choice: The sky>
In [21]: q.choice_set.create(c_text='Just hacking again', votes=0)
Out[21]: <Choice: Just hacking again>
In [23]: c = q.choice_set.create(c_text='tired', votes=0)
# Question 객체 확인
# 참조 : . 으로 참조
In [24]: c.question
Out[24]: <Question: what up?>
# 속성에 접근할 때는 .이 아니라 __로 접근
# Question의 pub_date의 year
In [25]: Choice.objects.filter(question__pub_date__year=current_year)
Out[25]: <QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>, <Choice: tired>]>
# 데이터베이스에서 삭제
In [26]: c.delete()
Out[26]: (1, {'polls.Choice': 1})
Admin
# polls/urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
# 정규표현식 : 아무것도 입력이 되지 않았을 경우
# views.index 호출
url(r'^$', views.index),
# 숫자 1개 이상은 question_id
# question_id를 view.detail에 넘겨줌
url(r'^(?P<question_id>[0-9]+)/$',
views.detail, name='detail'),
# ex: /polls/5/results/
url(r'^(?P<question_id>[0-9]+)/results/$',
views.results, name='results'),
# ex: /polls/5/vote/
url(r'^(?P<question_id>[0-9]+)/vote/$',
views.vote, name='vote'),
]
from django.http import HttpResponse
from .models import Question
def index(request):
return HttpResponse("Hello, world. You're at the polls site.")
def detail(request, question_id):
# pub_date 컬럼(필드)를 기준으로 내림차순 정렬(-pub_date, 마이너스)한 결과
latest_question_list = Question.objects.order_by('-pub_date')[:5]
# 돌려줄 문자열을 작성
output = ', '.join([q.question_text for q in latest_question_list])
# output2 = ''
# for q in latest_question_list:
# output2 += q.question_text + ', '
# output2 = output2[:-2]
return HttpResponse(output)
def results(request, question_id):
response = "You're looking at the results of question %s."
return HttpResponse(response % question_id)
def vote(request, question_id):
return HttpResponse("You're voting on question %s." % question_id)
디버그 하는법
Debug Configurations > + 버튼, python 선택
- Name : Django runserver
- Script: manage.py
- Script parameters: runserver
- Python interpreter : 설정환 가상환경으로 되어있나 확인
- Working directory : ~/projects/django-tutorial/django_all
브레이크 포인트를 output2 변수라인에 설정한다. 디버그 실행 후, 웹페이지에서 다시 접속하면 포인트에서 멈춘다. 그 때, request객체를 확인할 수 있다.
뷰와 분리하기
django_app/templates/polls/index.html
생성한다.
from django.template import loader
from .models import Question
# request : 사용자가 요청할때 담겨오는 것
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
# 템플릿 loader를 이용해서 'polls/index.html'에서 템플릿을 가져옴
template = loader.get_template('polls/index.html')
# 템플릿 파일에 전달할 context 객체를 정의
# 'latest_question_list' 키에 값을 할당
# 해당 키를 템플릿에서 사용
context = {
'latest_question_list': latest_question_list,
}
return HttpResponse(context, request)
위의 내용을 줄여 쓰면 아래와 같다.
# render() 함수 사용
def index(request):
latest_question_list = Question.objects.order_by('-pub_date')[:5]
context = {'latest_question_list': latest_question_list}
return render(request, 'polls/index.html', context)
템플릿 경로를 설정해준다.
# mysite/settings.py
import os
# BASE_DIR 장고 앱을 가르킴
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 서버 실행시 출력
# ~/projects/django_tutorial/django_app
print(BASE_DIR)
# 템플릿 디렉토리 추가
# 기본적으로 polls/templates/polls/를 찾기 때문에 알려줘야 함
TEMPLATES_DIR = os.path.join(BASE_DIR, 'templates')
# ~/projects/django_tutorial/django_app/templates
print(TEMPLATES_DIR)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
# 템플릿 검색 경로 추가
TEMPLATES_DIR,
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
과제
Django girls tutorial : Django모델 ~ CSS - 예쁘게 만들기(배포하기는 제외)