CEOS 17기 백엔드 파트에 합격해따!! 영광 ㅠ_ㅠ...
'Django REST API 서버 개발 및 배포'를 주제로 매주 스터디와 미션이 있다
Django는 처음 접해보기 때문에 차근차근 공부하며 과정을 기록해보겠다
Pycharm을 사용하는데 이미 prefessional 버전으로 설치가 되어있어서 설치 과정은 따로 적지 않겠음!
파이썬으로 개발할 때는 패키지 버전 호환이 중요하기 때문에 프로젝트마다 가상환경을 만들어서 관리한다
가상환경은 독립된 공간으로, 가상환경 내에 패키지가 설치되기 때문에 프로젝트별 패키지 관리에 용이하다
프로젝트 가상 환경을 생성하기 위해 Pycharm으로 프로젝트를 연다
Pycharm -> Preference(단축키 cmd + ,) -> Project -> Python Interpreter
-> Add Interpreter -> Add Local Interpreter
Virtualenv Enviroment를 선택하고 Base interpreter를 설정하여 'OK'를 눌러 가상환경을 생성해준다
가상환경이 제대로 설치되었다면 Pycharm Terminal에서 유저 정보 앞에 (가상환경이름)이 뜨는 것을 볼 수 있다
https://www.toptal.com/developers/gitignore
위의 사이트는 프로젝트에 맞는 gitignore 파일을 자동으로 생성해주는 유용한 사이트이다
나는 macOs를 사용하기 때문에 해당 사이트에서 옵션을 'Django'와 'macOs'로 설정하여 gitignore 파일을 생성했다
이제 Django를 설치해보자
Pycharm 터미널에 아래 명령어를 입력한다
% pip install django==3.2.16
설치가 완료되면
% pip list
pip 명령어로 Django가 제대로 설치되었는지 확인한다
pip list는 해당 가상환경에 설치된 모든 파이썬 라이브러리를 보여주는 명령어다
이제 프로젝트 초기 설정은 끝났다 이제 Django 튜토리얼을 본격적으로 시작해보겠당
https://docs.djangoproject.com/ko/3.2/intro/tutorial01/
위의 링크의 튜토리얼을 통해 간단한 설문조사 어플리케이션을 만드는 과정을 따라해보겠다
Pycharm 터미널에서 아래 명령어를 실행하여 현재 디렉토리에 'mysite'라는 디렉토리를 생성한다
% django-admin startproject mysite
사진과 같이 디렉토리 안에 'mysite'라는 패키지와 함께 .py 파일들이 생성된 것을 볼 수 있다
주요 파일들을 간단히 살펴보자
% python manage.py runserver
runserver 명령어는 기본적으로 8000번 포트로 개발 서버를 띄운다
만약 포트를 변경하고 싶다면 runserver 명령어 뒤에 원하는 포트 번호를 입력하면 된다
터미널에 다음과 같이 출력된다면 웹브라우저에서 http://127.0.0.1:8080/ 으로 접속했을 때 서버가 잘 띄워진 것을 볼 수 있다
이 Django 자체 서버는 개발 단계에서만 사용해야 하고 운영 단계에서는 사용하면 절대 안 된다!
앱을 생성하기 위해 manage.py가 존재하는 디렉토리에서 다음의 명령을 입력한다
% python manage.py startapp polls
상위 mysite 디렉토리 내에 polls라는 디렉토리가 추가된 것을 볼 수 있다
이렇게 Django는 앱의 기본 디렉토리 구조를 자동으로 생성해준다
여기서 잠깐! 잠시 Django의 MTV 패턴에 대해서 알아보겠다
MTV 패턴은 MVC 패턴과 동일하게 작동하는 패턴이지만 명칭만 다를 뿐이라고 한다
MTV 패턴에서 View는 MVC 패턴에서 Controller와 같은 역할을 한다
즉, HTTP 요청을 수신하여 HTTP 응답을 반환하는 요청 처리 함수이다
이제 첫 번째 뷰를 작성해보겠다
'polls/view.py'를 열어 다음과 같은 파이썬 코드를 입력한다
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
이어서 뷰를 호출하려면 이와 연결된 URL이 있어야 하는데, 이를 위해 URLconf를 생성해야 한다
'polls' 디렉토리 내에 'url.py' 파일을 만들고 아래 코드를 추가해준다
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
코드를 살펴보면
path()의 첫 번째 인자는 URL 패턴을 가진 문자열이다 해당 문자열과 일치하는 HTTP 요청이 들어오면
두 번째 인자인 view의 함수를 호출한다
세 번째 인자인 name 값은 URL 이름을 명확하게 구분짓기 위해 사용한다
다음 단계는 최상위 URLconf 에서 polls.urls 모듈을 바라보게 설정해야한다mysite/urls.py 파일에 django.urls.include를 import 하고, urlpatterns 리스트에 include() 함수를 다음과 같이 추가한다
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
path('admin/', admin.site.urls),
]
include() 함수의 역할은 다른 URLconf들을 참조할 수 있도록 도와주는 것이다
Django가 함수 include()를 만나게 되면, URL의 그 시점까지 일치하는 부분을 잘라내고 남은 문자열 부분을 후속 처리를 위해 include 된 URLconf로 전달한다
이제 runserver 명령어를 통해 서버를 띄우고 웹브라우저에
http://127.0.0.1:8000/polls/ 를 치면
위와 같은 화면이 제대로 보인다!
mysite/setting.py로 들어가서 확인해보면, Django 프로젝트의 데이터베이스는 기본적으로 'SQLite'로 설정되어있는 것을 볼 수 있다
SQLite는 Python에서 제공하는 데이터베이스로 별도로 설치할 필요가 없다
MySQL, PostgreSQL과 같은 다른 데이터베이스를 사용하고 싶다면 DATABASES 설정을 변경하고 USER, PASSWORD, HOST 등을 추가 설정해주면 된다
이 튜토리얼에서는 SQLite를 그대로 사용하도록 하겠다!
Django의 TIME_ZONE은 기본적으로 UTC로 되어있는데, 이를 한국 시간으로 바꾸겠다
mysite/setting.py에서 TIME_ZONE을 'Asia/Seoul'로 변경하고 USE_TZ를 'False'로 바꾸어 바뀐 타임존이 적용되게 설정한다
setting.py 위쪽을 보면 INSTALLED_APPS 항목이 있다
이는 현재 Django 인스턴스에서 활성화된 모든 Django 어플리케이션들을 보여준다
이러한 기본 어플리케이션들을 사용하기 위해 데이터베이스 테이블을 만들어야한다
아래 명령어를 실행하여 데이터베이스 테이블을 생성하자
% python manage.py migrate
migrate 명령은 INSTALLED_APPS 설정을 확인하고 mysite의 데이터베이스 설정에 따라 필요한 데이터베이스 테이블을 생성한다
위는 실행 결과 터미널 화면이다
여기서 Model이란 MTV 패턴의 Model을 말한다
Model은 응용프로그램의 데이터 구조를 정의하고 데이터베이스의 기록을 관리(추가, 수정, 삭제)하고 쿼리하는 방법을 제공하는 파이썬 객체이다
질문과 선택이라는 두 가지 모델을 만들어 볼 것이다
질문 모델에는 질문과 게시 날짜 필드가 있고, 선택 모델에는 선택 텍스트와 투표 집계 필드가 있다
각 선택은 질문과 연결되고, 이를 Python 클래스로 표현한다
polls/models.py 파일에 아래 코드를 추가한다
from django.db import models
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
데이터베이스의 각 필드는 Field 클래스의 인스턴스로 표현된다
CharField는 문자 필드를 표현하고, DateTimeField는 날짜와 시간 필드를 표현한다
Field는 다양한 선택적 인수들을 가질 수 있다
ForeignKey는 말 그대로 외래키를 표현한다
Django는 다대일(many-to-one), 다대다(many-to-many), 일대일(one-to-one) 과 같은 모든 일반 데이터베이스의 관계들를 지원한다
위의 코드는 하나의 Choice와 Question의 다대일 관계를 나타낸다
Django는 모델을 통해 데이터베이스 스키마를 생성(CREATE TABLE 문)하고,
Question과 Choice 객체에 접근하기 위한 Python 데이터베이스 접근 API를 생성한다
생성한 앱을 현재 프로젝트에 포함시키려면 Config 클래스를 setting.py의 INSTALLED_APPS에 추가해야 한다
PollsConfig 클래스는 polls/apps.py 파일 내에 존재한다
이 클래스의 경로를 setting.py 파일에 추가해준다
이제 아래 명령어를 터미널에서 실행해준다
% python manage.py makemigrations polls
makemigrations 명령어를 통해 모델 생성 및 변경을 원한다는 것을 Django에게 알려준다
python manage.py sqlmigrate polls 0001
sqlmigrate 명령어를 사용하면 실행하는 sql 문을 볼 수 있다
migrate 하기 전에 sql문을 검토하고 모델을 수정할 수 있다
이제 migrate 명령어를 통해 모델에서의 변경 사항들과 데이터베이스의 스키마를 동기화한다
python manage.py migrate
결론! 모델을 생성 및 수정 후에
makemigrations 명령어를 통해 마이그레이션을 만들고
migrate 명령어로 변경사항을 데이터베이스에 적용한다
마이그레이션을 만드는 명령과 적용하는 명령이 분리된 것은 버전 관리 시스템에 마이그레이션을 커밋하고 앱과 함께 출시할 수 있도록 하기 위해서라고 한다
위의 사진과 같이 Pycharm 터미널에서 쉘에 진입 후 데이터베이스 API를 사용해보았다
Question 인스턴스를 생성해서 데이터베이스에 저장하는 과정이다
인스턴스 q는 id값 1을 가진다
현재 objects.all()을 사용했을 때 조금 더 알아보기 쉽도록 함수를 만들어주겠다
위와 같이 __str__ 함수를 작성했다
__str__ 함수는 해당 클래스로 만들어진 인스턴스를 출력할 때, 문자열로 설명해준다
변경 사항이 잘 적용된 것을 볼 수 있다
이렇게 쉘에서 다양한 데이터베이스 API를 사용해보았다
sql 쿼리문을 직접 작성하지 않아도 된다는 점이 굉장히 편리했다
Django는 모델에 대한 관리자 페이지를 지원한다
% python manage.py createsuperuser
위의 명령어를 통해 username, email, password 설정하면 관리자가 생성된다
이제 runserver 명령어를 통해 서버를 실행하고
웹브라우저에서 http://127.0.0.1:8000/admin/ 로 접속하면 관리자 페이지가 뜬다
관리자 페이지에 poll 앱을 등록하려면 polls/admin.py에 다음과 같은 코드를 추가한다
from django.contrib import admin
from .models import Question
admin.site.register(Question)
그리고 페이지를 새로고침 하면 Question 모델이 표시된다
Question 모델을 클릭해서 들어가면
생성된 데이터 객체들이 보이고 Question 모델에 대한 crud를 할 수 있다
정말 편리하다...ㄷ ㄷ
이제 View를 추가해보겠다 목록은 다음과 같다
위와 같이 polls/views.py에 view를 추가했다
이어서 polls/urls.py에 코드를 추가해 추가한 view를 연결한다
이제 웹브라우저에서 http://127.0.0.1:8000/polls/34/ 로 들어가면
위와 같은 페이지가 출력된다
사용자가 '/polls/34/'를 요청하면 Django는 먼저 mysite.urls 파이썬 모듈을 불러온다
mysite.urls에서 urlpatterns라는 변수를 찾고, 순서대로 패턴을 따라간다
'polls/'를 찾은 후엔, 일치하는 텍스트("polls/")를 버리고, 남은 텍스트인 "34/"를 'polls.urls' URLconf로 전달한다
'<int:question_id>/'에서 question_id가 34이므로 결과적으로 detail() 뷰 함수에 34가 전달되며 호출된다
각 뷰는 요청된 페이지의 내용이 담긴 HttpResponse 객체를 반환하거나, Http 예외를 발생하게 해야한다
Django에서 제공하는 데이터베이스 API를 사용해서 뷰에 기능을 추가해보겠다
index() 뷰 하나를 호출했을 때, 시스템에 저장된 최소한 5 개의 투표 질문이 콤마로 분리되어 발행일에 따라 출력된다
이제 template을 만들어보겠다
여기서 잠깐! template은 MVC 패턴에서 view에 해당한다
즉 파일의 구조나 레이아웃을 정의하고(예: HTML 페이지), 실제 내용을 보여주는 데 사용되는 플레이스홀더를 가진 텍스트 파일이다
뷰는 템플릿을 이용하여 동적으로 페이지를 만들고 모델에서 가져온 데이터로 채운다
polls 디렉토리에 templates 디렉토리를 만들고 그 안에 polls 디렉토리를 만든다
뷰는 polls/templates/polls/에 저장된다
이제 index 뷰를 다음과 같이 수정해보자
index 뷰는 polls/index.html 템플릿을 불러온 후, context를 전달한다
브라우저에서 '/polls/' 페이지를 불러오면, Question 모델의 데이터들이 출력된다
이때 render를 사용하면 loader와 HttpResponse를 import하지 않아도 된다
render() 함수는 request 객체를 첫 번째 인수로 받고, 템플릿 이름을 두 번째 인수로 받으며, context 사전형 객체를 세 번째 선택적 인수로 받는다
from django.http import Http404
from django.shortcuts import render
from .models import Question
# ...
def detail(request, question_id):
try:
question = Question.objects.get(pk=question_id)
except Question.DoesNotExist:
raise Http404("Question does not exist")
return render(request, 'polls/detail.html', {'question': question})
detail view에 추가할 코드이다
코드를 살펴보면 요청 받은 question_id가 없는 경우 Http404 예외를 발생시킨다
이를 get_object_or_404() 를 통해 아래 코드와 같이 간단하게 작성할 수 있다
from django.shortcuts import get_object_or_404, render
from .models import Question
# ...
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'polls/detail.html', {'question': question})
get_object_or_404() 함수는 객체가 존재하지 않을 경우 Http404 예외를 발생시킨다
이와 비슷하게 get_list_or_404() 함수도 존재하는데, 이는 리스트가 비어있는 경우 404 예외를 발생시킨다
튜토리얼의 프로젝트는 polls라는 앱 하나만 가지고 진행했으나, 실제 Django 프로젝트는 앱이 여러 개일 수 있다
그렇기에 앱들의 url을 구분하기 위해서 URLconf에 namespace를 추가해야한다polls/urls.py 파일에 app_name을 추가하여 어플리케이션의 namespace를 설정할 수 있다
이제 polls/views.py의 vote() 함수를 다음과 같이 수정해준다
코드를 하나씩 살펴보자
request.POST:
request.POST는 키로 전송된 자료에 접근할 수 있도록 해주는 객체로 파이썬의 dictionary 자료형과 유사하다
request.POST['choice'] 는 선택된 Choice의 ID를 문자열로 반환한다
만약 POST 자료에 choice 가 없으면 KeyError가 발생한다 위의 코드는 KeyError 를 체크하고, choice가 주어지지 않은 경우에는 에러 메시지와 함께 설문조사 폼을 다시 보여준다
HttpResponseRedirect:
설문지의 수가 증가한 이후에 코드는 redirect 할 URL을 인수로 받아 HttpResponseRedirect 를 반환한다
reverse():
HttpResponseRedirect 생성자 안에서 reverse() 함수를 사용한다
reverse() 함수는 제어를 전달하기 원하는 뷰의 이름과, URL패턴의 변수를 인수로 가진다
따라서 '/polls/<int:question_id>/results/'로 redirect 될 것이다
index 뷰와 비슷하게 result 뷰와 템플릿을 작성해준다
polls/admin.py에 Choice 모델을 추가해주고
관리자 페이지에서 데이터를 추가해주었다
웹브라우저에서 '/polls/1/'로 접속하면 투표 페이지가 뜬다!
현재 index(), detail(), result() 뷰는 코드가 중복된다
이러한 뷰는 URL에서 전달 된 매개 변수에 따라 데이터베이스에서 데이터를 가져 오는 것과 템플릿을 로드하고 렌더링 된 템플릿을 리턴하는 기본 웹 개발의 일반적인 경우이다
Django는 이런 일반적인 경우를 위해 '제너릭 뷰'를 제공한다
이제 이 코드들을 제너릭 뷰로 리팩토링 해보겠다
먼저 polls/url.py에서 변수를 id값이 아닌 pk로 변경한다
이어서 view들을 위와 같이 수정해준다
view들을 함수가 아닌 class로 작성하여 각각 기능에 맞게 제너릭 뷰를 가져온다
다시 정리하면, model을 통해 모델 이름을 명시하거나
모델의 일부 데이터만 필요한 경우 get_queryset 함수를 통해 일부만 가져온다
그리고 template_name에 연결하고자 하는 템플릿 html의 위치와 파일명을 지정해준다
여기까지 Django 튜토리얼을 따라해보았다
처음 해보는 거라 좀 헷갈리지만... 천천히 다시 읽어보면서 공부해야겠다!