[ 생활코딩 - Web2 Python ] Django Framework - CRUD 구현
Django 설치 및 포트 접속
$ pip install django
$ django-admin startproject project-name
$ cd project-name
$ python manage.py runserver
$ django-admin startapp myapp
- 127.0.0.1:8000 접속 후 아래 화면 뜨면 포트 접속 성공
- 포트 번호 직접 지정 가능
$ python manage.py runserver 8888
라우팅
- 어떤 프레임워크를 쓰더라도 라우팅이 가장 중요
- myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('myapp.urls'))
]
- myapp/urls.py
from django.contrib import admin
from django.urls import path
from myapp import views
urlpatterns = [
path('', views.index),
path('create/', views.create),
path('read/<id>',views.read),
]
- myapp/views.py
from django.shortcuts import render , HttpResponse
def index(request):
return HttpResponse('Welcome!')
def create(request):
return HttpResponse('Create!')
def read(request, id):
return HttpResponse('Read! '+id)
- 과정예시
1. 127.0.0.1/read/1 접속
2. django는path('', include('myapp.urls'))로 감
3. myapp.urls로 위임
4.path('read/<id>',views.read)로 감
5. views.read로 위임
6. HttpResponse에 ('Read! '+id)값을 더해서 클라이언트에 보내줌
Web Server vs. Web Application Server
# Web Server
- 정적 (static)
- apache, nginxm IIS
- 필요할만한 웹 페이지를 미리 만들어야함 (1.html, 2.html, 3.html)
- 빠르고, 준비할 것이 적음
# Web Appliccation Server
- 동적 (dynamic)
- django, flask, php, jsp, ROL
- 하나만 만들어도 됨 (view.py)
- 느리고, 공부할 것이 많음
- 유지보수 좋음 (view.py 만 수정하면 됨)
- 개인화된 정보를 생성할 수 있음
읽기 기능 구현 (READ)
- topic 딕셔너리로 구성된 topics 리스트 생성
- 각각의 topic 링크 클릭하면 아래에 title과 body가 출력되도록 함
- HTMLTemplate 함수를 선언하여 공통 html 부분을 구현
- 파라미터로 article을 받음
- read 험수에서 article에 title과 body값을 작성하여 인자로 넘겨줌
from django.shortcuts import render, HttpResponse
topics = [
{'id': 1, 'title': 'routing', 'body': 'routing is..'},
{'id': 2, 'title': 'view', 'body': 'view is..'},
{'id': 3, 'title': 'model', 'body': 'model is..'}
]
def HTMLTemplate(articleTag):
global topics
str = ''
for topic in topics:
str+=f'<li><a href="/read/{topic["id"]}">{topic["title"]}</a></li>'
return f'''
<html>
<body>
<h1><a href="/">Django</a></h1>
<ol>
{str}
</ol>
{articleTag}
</body>
</html>
'''
def index(request):
article='''<h2>Welcome</h2>
<p>Hello, django</p>'''
return HttpResponse(HTMLTemplate(article))
def read(request, id):
global topics
article =''
for topic in topics:
if str(topic["id"]) == id:
article = f'<h2>{topic["title"]}</h2><p>{topic["body"]}</p>'
return HttpResponse(HTMLTemplate(article))
쓰기 기능 구현 (CREATE)
- csrf기능 적용하지 않기 : https://stackoverflow.com/questions/16458166/how-to-disable-djangos-csrf-validation 참고
- csrf_exempt, method_decorator import
- create 기능 구현 후 페이지 redirct 하기 위해 redirect도 import 할 것
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from django.shortcuts import render, HttpResponse, redirect
- create 전과 후를 구분 짓기 위해 if문으로 request.method 가 GET일 때와 POST일 때를 나누어 구현
-request.method 가 GET : create 링크 클릭 시 title, body를 입력할 수 있는 칸이 생기고 title과 body 입력 후 create 버튼 누르면 post 방식으로 내용이 전달됨
- request.method 가 POST : 해당 내용을 포함한 새로운 딕셔너리를 생성하고 topics에 append
- 방금 create한 내용을 출력하기 위해 /read/id값 으로 redirect함
@method_decorator(csrf_exempt, name='dispatch')
def create(request):
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" rows=6></textarea></p>
<p><input type="submit" value="create"></p>
</form>'''
return HttpResponse(HTMLTemplate(article))
elif request.method == "POST":
title = request.POST["title"]
body = request.POST["body"]
newTopic ={'id':len(topics)+1, 'title':title, 'body':body}
topics.append(newTopic)
url = '/read/'+str(newTopic["id"])
return redirect(url)
삭제 기능 구현 (Delete)
<템플릿 수정>
- 파라미터에 id 값 추가 / 기본값은 None
- 기본 화면에서는 id 값이 없으므로 delete 버튼 보이지 않고,
id 값이 있는 topic 클릭시에만 delete 버튼 보이도록 함
- hidden type의 id값이 post 방식으로 /delete/에 전송됨
def HTMLTemplate(articleTag, id=None):
global topics
contextDelete = ''
if id!=None:
contextDelete = f'''<li>
<form action="/delete/" method="post">
<input type="hidden" name="id" value={id}>
<input type="submit" value="delete">
</form>
</li>'''
str = ''
for topic in topics:
str+=f'<li><a href="/read/{topic["id"]}">{topic["title"]}</a></li>'
return f'''
<html>
<body>
<h1><a href="/">Django</a></h1>
<ol>
{str}
</ol>
{articleTag}
<ul>
<li><a href="/create">Create</a></li>
{contextDelete}
</ul>
</body>
</html>
'''
<delete 함수>
- 빈 배열 newTopics 생성
- POST방식으로 전달받은 id값과 일치하는 topic을 제외하고 다른 topic들은 빈 배열에 append
- append 된 배열 newTopics를 topics로 대체
- 기본 홈 화면으로 redirect
@method_decorator(csrf_exempt, name='dispatch')
def delete(request):
global topics
if request.method == 'POST':
id = request.POST['id']
newTopics = []
for topic in topics:
if topic['id'] != int(id):
newTopics.append(topic)
topics = newTopics
return redirect('/')
수정 기능 구현 (Update)
<템플릿 수정>
- update 링크 추가
contextStr = ''
if id!=None:
contextStr = f'''
<li>
<a href="/update/{id}">Update</a>
</li>
<li>
<form action="/delete/" method="post">
<input type="hidden" name="id" value={id}>
<input type="submit" value="delete">
</form>
</li>
'''
update 함수 구현
@method_decorator(csrf_exempt, name='dispatch')
def update(request,id):
global topics
if request.method == "GET":
for t in topics:
if t["id"] == int(id):
selectedTopic = {'title':t["title"], 'body':t["body"]}
article = f'''
<form action="/update/{id}/" method="post">
<p><input type="text" name="title" value={selectedTopic["title"]}></p>
<p><textarea name="body" rows=6>{selectedTopic["body"]}</textarea></p>
<p><input type="submit" value="update"></p>
</form>'''
return HttpResponse(HTMLTemplate(article,id))
elif request.method == "POST":
title = request.POST["title"]
body = request.POST["body"]
for t in topics:
if t["id"] == int(id):
t["title"] = title
t["body"] = body
url = '/read/'+ str(id)
return redirect(url)