Django 소개
참고 강의 : (유튜브)생활코딩 - Python Django Framework
1. Web Framework
-
웹 애플리케이션을 만들기 위해 만들어둔 공통적인 framework
-
웹 페이지를 만드는 프로그램을 만들고,
요청이 들어오면 해당 프로그램으로 새 웹페이지를 만들어줌!
-
ex) Django
django 설치 : pip install django
django-admin
- sub명령들 확인
django-admin startproject myproject .
- 현재 경로(.)에 myproject라는 이름의 프로젝트 폴더 생성
- 생성되는 파일/폴더
myproject
(폴더)settings.py
: 프로젝트를 운영하는데 필요한 설정들urls.py
: 사용자가 접속하는 path를 routing해주는 역할
manage.py
- 프로젝트 운영에 필요한 util 파일
python3 manage.py
- 사용 가능한 명령어들 확인 가능
python manage.py runserver
- django 기본 서버 : http://127.0.0.1:8000/
- ctrl +C : 서버 종료
이미 8000번 포트가 사용 중이라면? 다른 포트 사용 가능!
python manage.py runserver 8888
2. 전체적인 Framework
- 사용자가 접속하면, project 내의
urls.py
는 적절한 app으로 보내줌 - 해당 app안에 있는
urls.py
는 적당한 view 내의 함수로 보내줌 - model을 통해서 DB에 접속하고, DB에서 받아온 정보를 (html/json/xml 등의 형태로) 다시 응답해줌
app 만들기
django-admin startapp myapp
- myapp이라는 이름의 app을 생성(시작)
Routing
사용자가 접속한 경로를 적절한 곳으로 보내주기
myproject 폴더 내의 urls.py
-
urlpatterns
라는 리스트를 반드시 가지고 정의해야하고,그 안에는 routing에 관한 정보가 담겨 있어야한다.
ex) http://127/0.0.1/에 접속했을 때, myapp내의 view로 routing시켜주려면?
ex) `http://127/0.0.1/temp/에 ~ myapp2~
[ myproject 내의 urls.py
]
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('myapp.urls')),
path('temp', include('myapp2.urls'))
]
- 이와 같이 수정한 뒤, 위
urls.py
파일을 복사해서 myapp내에 붙여넣는다.
[ myapp 내의 urls.py
]
ex) http://127/0.0.1/create에 접속했을 때
ex) http://127/0.0.1/read/1에 접속했을 때
urlpatterns = [
path(''),
path('create/'),
path('read/1/'),
]
[ myapp 내의 views.py
]
- index함수를 실행하면, Welcome! 이 뜨도록 한다.
- create함수를 실행하면, Create! 이 뜨도록 한다.
- read함수를 실행하면, Read! 이 뜨도록 한다.
from django.shortcuts import render, HttpResponse
def index(request):
return HttpResponse('Welcome!')
def create(request):
return HttpResponse('Create!')
def read(request):
return HttpResponse('Read!')
만약, 사용자가….
- 1) 아무런 경로를 지정하지 않고 접속할 경우 : views 내의
index
함수로 보내줌 - 2) create 경로로 접속할 경우 : views 내의
create
함수로 보내줌 - 3) read/1 경로로 접속할 경우 : views 내의
read
함수로 보내줌
from myapp import views
urlpatterns = [
path('', views.index),
path('create/', views.create),
path('read/1/', views.read),
]
궁금증 : 저기서, read/1
에서 1
대신 다른 (가변적인) 숫자들이 와도 되지 않을까?
[ myapp 내의 urls.py
] 수정하기
urlpatterns = [
path('', views.index),
path('create/', views.create),
path('read/<id>/', views.read),
]
[ myapp 내의 views.py
] 수정하기
def read(request, id):
return HttpResponse('Read!' + id)
Web Server vs Web Application Server
Web Server :
-
필요로 하는 웹을 미리 만들어놔야함
-
static & 빠르다
Web Application Server :
- 웹 페이지를 생성해내는 “프로그램” 하나를 만들어냄
view.py
하나만 바꾸면 전부 변경 가능!
- dynamic & 느리다
3. CRUD
(1) Read
from django.shortcuts import render, HttpResponse
topic_text1 = {
'id':1,
'title':'Routing',
'body':'Routing is ...'
}
topic_text2 = {
'id':2,
'title':'View',
'body':'View is ...'
}
topic_text3 = {
'id':3,
'title':'Model',
'body':'Model is ...'
}
topics = [topic_text1, topic_text2, topic_text3]
def index(request):
global topics
ol = ''
for topic in topics:
ol += f'<li><a href="/read/{topic["id"]}">{topic["title"]}</li>'
return HttpResponse(f'''
<html>
<body>
<h1>Django</h1>
<ol>
{ol}
</ol>
<h2>Welcome</h2>
Hello, Django
</body>
</html>
''')
def create(request):
return HttpResponse('Create!')
def read(request, id):
return HttpResponse('Read!' + id)
결과 :
- 1) 메인 화면에 접속할 경우
- 2-1) Routing 클릭했을 경우 :
127.0.0.1:8000/read/1/
로 라우팅 - 2-2) Routing 클릭했을 경우 :
127.0.0.1:8000/read/2/
로 라우팅 - 2-3) Routing 클릭했을 경우 :
127.0.0.1:8000/read/3/
로 라우팅
우선, 위의 HttpResponse~ 내의 내용들이 매우 길기 때문에, 함수로 만들 것이다.
( + “create 링크” & “delete 폼” 맨 하단에 생성 )
- index 함수 수정
- HTMLTemplate 함수 생성
def HTMLTemplate(articleTag):
global topics
ol = ''
for topic in topics:
ol += f'<li><a href="/read/{topic["id"]}">{topic["title"]}</a></li>'
return HttpResponse(f'''
<html>
<body>
<h1><a href="/">Django</a></h1>
<ul>
{ol}
</ul>
{articleTag}
<ul>
<li><a href="/create/">create</a></li>
</ul>
</body>
</html>
''')
def index(request):
article = '''
<h2>Welcome</h2>
Hello, Django
'''
return HttpResponse(HTMLTemplate(article))
이제 read
함수를 수정하면 될 것이다!
def read(request, id):
global topics
article = ''
for topic in topics:
if topic['id'] == int(id):
article = f'<h2>{topic["title"]}</h2>{topic["body"]}'
return HttpResponse(HTMLTemplate(article))
(2) Create (Write)
목표 : 다음과 같이 입력란(폼)을 만들고, 제출 버튼을 누르면, topics 리스트에 새로운 내용이 추가되도록!
def create(request):
article = '''
<form action="/create/">
<p><input type="text" name="title" placeholder="title"></p>
<p><textarea type="text" name="body" placeholder="body"></textarea></p>
<p><input type='submit'></p>
</form>
'''
return HttpResponse(HTMLTemplate(article))
<form>
: 담겨있는 내용들을 원하는 path로 보내주기 위함
해당 form안에 내용을 작성해서 “제출”을 누르면…?
[ Request Method ] GET vs POST
- GET : 주로 내용을 읽어들일 때 ( 내용 숨김 X )
- http://localhost:8000/read/1/
- http://localhost:8000/read/?id=1/ ( query string )
- POST : 주로 내용을 작성할 때 ( 내용 숨김 O )
- header안에 내용을 숨겨서 보내기!
<form action="/create/" method="post">
에러 방지 위해… ( 내용 ski p )
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def create(request):
article = '''
<form action="/create/" method="post">
<p><input type="text" name="title" placeholder="title"></p>
<p><textarea type="text" name="body" placeholder="body"></textarea></p>
<p><input type='submit'></p>
</form>
'''
return HttpResponse(HTMLTemplate(article))
@csrf_exempt
를, 면제시키고 싶은 함수 앞에 decorator로 넣기
GET & POST 방식 다르게 처리하기
@csrf_exempt
def create(request):
global nextId
if request.method =='GET':
article = '''
<form action="/create/" method="post">
<p><input type="text" name="title" placeholder="title"></p>
<p><textarea name="body" placeholder="body"></textarea></p>
<p><input type="submit"></p>
</form>
'''
return HttpResponse(HTMLTemplate(article))
elif request.method =='POST':
title = request.POST['title']
body = request.POST['body']
newTopic = {"id": nextId,
"title":title,
"body":body}
topics.append(newTopic)
url_to_move = '/read/' + str(nextId)
nextId += 1
return redirect(url_to_move)
(3) Delete
- HttpTemplate함수 내에, “delete 폼”을 생성한다.
- read 템플릿에서, id값도 반환해서 뭘 삭제할지 알려준다.
- delete 버튼은,
- home 화면에서는 보이지 않고
- 상세 링크화면에서만 보이도록!
def HTMLTemplate(articleTag, id=None):
global topics
# (case 1) home 화면일 경우
context_UI = ''
# (case 2) 상세 링크일 경우
if id!=None:
context_UI = f'''
<li>
<form action="/delete/" method="post">
<input type="hidden" name="id" value={id}>
<input type="submit" value="delete">
</form>
</li>
'''
ol = ''
for topic in topics:
ol += f'<li><a href="/read/{topic["id"]}">{topic["title"]}</a></li>'
return HttpResponse(f'''
<html>
<body>
<h1><a href="/">Django</a></h1>
<ul>
{ol}
</ul>
{articleTag}
<ul>
<li><a href="/create/">create</a></li>
{context_UI}
</ul>
</body>
</html>
''')
def read(request, id):
global topics
article = ''
for topic in topics:
if topic['id'] == int(id):
article = f'<h2>{topic["title"]}</h2>{topic["body"]}'
return HttpResponse(HTMLTemplate(article, id))
delete
함수
@csrf_exempt
def delete(request):
global topics
if request.method == 'POST':
id = request.POST['id']
# 해당 id 제거 = 해당 id 제외 나머지만 remain
remained_Topics = []
for topic in topics:
if topic['id'] != int(id):
remained_Topics.append(topic)
topics = remained_Topics
return redirect('/')
urls.py
에 방금 만든 delete
함수 불러오는 path 추가하기
urlpatterns = [
path('', views.index),
path('create/', views.create),
path('read/<id>/', views.read),
path('delete/', views.delete)
]
(4) Update
delete와 마찬가지로, context_UI
에 update 버튼도 추가
( context_UI
: home화면에서는 안뜨고, 상세 링크에서만 뜨는 UI )
def HTMLTemplate(articleTag, id=None):
global topics
# (case 1) home 화면일 경우
context_UI = ''
# (case 2) 상세 링크일 경우
if id!=None:
context_UI = f'''
<li>
<form action="/delete/" method="post">
<input type="hidden" name="id" value={id}>
<input type="submit" value="delete">
</form>
</li>
<li>
<a href="/update/{id}">update</a>
</li>
'''
ol = ''
for topic in topics:
ol += f'<li><a href="/read/{topic["id"]}">{topic["title"]}</a></li>'
return HttpResponse(f'''
<html>
<body>
<h1><a href="/">Django</a></h1>
<ul>
{ol}
</ul>
{articleTag}
<ul>
<li><a href="/create/">create</a></li>
{context_UI}
</ul>
</body>
</html>
''')
update
함수 구현하기
@csrf_exempt
def update(request, id):
global topics
if request.method == 'GET':
for topic in topics:
if topic['id'] == int(id):
selectedTopic = {
'title':topic['title'],
'body':topic['body']
}
article = f'''
<form action="/update/{id}" method="post">
<p><input type="text" name="title" placeholder="title" value={selectedTopic['title']}></p>
<p><textarea name="body" placeholder="body">{selectedTopic['body']}</textarea></p>
<p><input type="submit"></p>
</form>
'''
return HttpResponse(HTMLTemplate(article, id))
elif request.method == 'POST':
title = request.POST['title']
body = request.POST['body']
for topic in topics:
if topic['id'] == int(id):
topic['title'] = title
topic['body'] = body
return redirect(f'/read/{id}')
urls.py
에 방금 만든 update
함수 불러오는 path 추가하기
urlpatterns = [
path('', views.index),
path('create/', views.create),
path('read/<id>/', views.read),
path('delete/', views.delete),
path('update/<id>', views.update)
]