[CEOS] 1주차 미션: Django Tutorial

HAEN·2023년 3월 25일
1

CEOS 17기 백엔드 파트에 합격해따!! 영광 ㅠ_ㅠ...
'Django REST API 서버 개발 및 배포'를 주제로 매주 스터디와 미션이 있다
Django는 처음 접해보기 때문에 차근차근 공부하며 과정을 기록해보겠다
Pycharm을 사용하는데 이미 prefessional 버전으로 설치가 되어있어서 설치 과정은 따로 적지 않겠음!


1. 프로젝트 생성

(1) 가상환경 생성

파이썬으로 개발할 때는 패키지 버전 호환이 중요하기 때문에 프로젝트마다 가상환경을 만들어서 관리한다
가상환경은 독립된 공간으로, 가상환경 내에 패키지가 설치되기 때문에 프로젝트별 패키지 관리에 용이하다

프로젝트 가상 환경을 생성하기 위해 Pycharm으로 프로젝트를 연다

Pycharm -> Preference(단축키 cmd + ,) -> Project -> Python Interpreter
-> Add Interpreter -> Add Local Interpreter

Virtualenv Enviroment를 선택하고 Base interpreter를 설정하여 'OK'를 눌러 가상환경을 생성해준다

가상환경이 제대로 설치되었다면 Pycharm Terminal에서 유저 정보 앞에 (가상환경이름)이 뜨는 것을 볼 수 있다

(2) gitignore 파일 생성

https://www.toptal.com/developers/gitignore

위의 사이트는 프로젝트에 맞는 gitignore 파일을 자동으로 생성해주는 유용한 사이트이다
나는 macOs를 사용하기 때문에 해당 사이트에서 옵션을 'Django'와 'macOs'로 설정하여 gitignore 파일을 생성했다

(3) Django 설치

이제 Django를 설치해보자
Pycharm 터미널에 아래 명령어를 입력한다

% pip install django==3.2.16

설치가 완료되면

% pip list

pip 명령어로 Django가 제대로 설치되었는지 확인한다
pip list는 해당 가상환경에 설치된 모든 파이썬 라이브러리를 보여주는 명령어다

이제 프로젝트 초기 설정은 끝났다 이제 Django 튜토리얼을 본격적으로 시작해보겠당


2. Django 앱 작성하기 part 1

https://docs.djangoproject.com/ko/3.2/intro/tutorial01/

위의 링크의 튜토리얼을 통해 간단한 설문조사 어플리케이션을 만드는 과정을 따라해보겠다

(1) 프로젝트 생성

Pycharm 터미널에서 아래 명령어를 실행하여 현재 디렉토리에 'mysite'라는 디렉토리를 생성한다

% django-admin startproject mysite

사진과 같이 디렉토리 안에 'mysite'라는 패키지와 함께 .py 파일들이 생성된 것을 볼 수 있다
주요 파일들을 간단히 살펴보자

  • 외부 mysite 디렉토리: 프로젝트의 컨테이너. 이름은 원하는 대로 설정 가능하다
  • manage.py: Django 프로젝트와 다양한 방법으로 상호작용 하는 커맨드라인의 유틸리티
  • 내부 mysite 디렉토리: 프로젝트를 위한 실제 Python 패키지들이 저장되는 디렉토리 이 디렉토리 내의 이름을 이용하여 (mysite.urls 와 같은 식으로) 프로젝트의 어디서나 Python 패키지들을 import 할 수 있음
  • mysite/__init__.py: 상위 디렉토리를 패키지처럼 다루라고 알려주는 용도 빈 파일
  • mysite/settings.py: 현재 Django 프로젝트의 환경 및 구성을 저장하는 파일
  • mysite/urls.py: 현재 Django project 의 URL 선언을 저장하는 파일

이제 서버를 띄워보겠다 cd 명령어를 통해 mysite 디렉토리로 이동하여 아래 명령어를 실행한다
% python manage.py runserver

runserver 명령어는 기본적으로 8000번 포트로 개발 서버를 띄운다
만약 포트를 변경하고 싶다면 runserver 명령어 뒤에 원하는 포트 번호를 입력하면 된다

터미널에 다음과 같이 출력된다면 웹브라우저에서 http://127.0.0.1:8080/ 으로 접속했을 때 서버가 잘 띄워진 것을 볼 수 있다

이 Django 자체 서버는 개발 단계에서만 사용해야 하고 운영 단계에서는 사용하면 절대 안 된다!

(2) 앱 생성

앱을 생성하기 위해 manage.py가 존재하는 디렉토리에서 다음의 명령을 입력한다

% python manage.py startapp polls

상위 mysite 디렉토리 내에 polls라는 디렉토리가 추가된 것을 볼 수 있다
이렇게 Django는 앱의 기본 디렉토리 구조를 자동으로 생성해준다

(3) View 작성

여기서 잠깐! 잠시 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/ 를 치면

위와 같은 화면이 제대로 보인다!


3. Django 앱 작성하기 part 2

(1) 데이터베이스 설정 및 setting 변경

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의 데이터베이스 설정에 따라 필요한 데이터베이스 테이블을 생성한다

위는 실행 결과 터미널 화면이다

(2) Model 작성

여기서 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를 생성한다

(3) Model 활성화

생성한 앱을 현재 프로젝트에 포함시키려면 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 명령어로 변경사항을 데이터베이스에 적용한다
마이그레이션을 만드는 명령과 적용하는 명령이 분리된 것은 버전 관리 시스템에 마이그레이션을 커밋하고 앱과 함께 출시할 수 있도록 하기 위해서라고 한다

(4) Django API 사용해보기

위의 사진과 같이 Pycharm 터미널에서 쉘에 진입 후 데이터베이스 API를 사용해보았다
Question 인스턴스를 생성해서 데이터베이스에 저장하는 과정이다
인스턴스 q는 id값 1을 가진다

  • 모델명.objects.all(): 데이터베이스 테이블에 생성된 모든 데이터를 가져옴

현재 objects.all()을 사용했을 때 조금 더 알아보기 쉽도록 함수를 만들어주겠다

위와 같이 __str__ 함수를 작성했다
__str__ 함수는 해당 클래스로 만들어진 인스턴스를 출력할 때, 문자열로 설명해준다

변경 사항이 잘 적용된 것을 볼 수 있다

이렇게 쉘에서 다양한 데이터베이스 API를 사용해보았다
sql 쿼리문을 직접 작성하지 않아도 된다는 점이 굉장히 편리했다

(5) 관리자 생성

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를 할 수 있다

정말 편리하다...ㄷ ㄷ


4. Django 앱 작성하기 part 3

(1) view 추가

이제 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가 전달되며 호출된다

(2) View에 기능 추가

각 뷰는 요청된 페이지의 내용이 담긴 HttpResponse 객체를 반환하거나, Http 예외를 발생하게 해야한다
Django에서 제공하는 데이터베이스 API를 사용해서 뷰에 기능을 추가해보겠다

index() 뷰 하나를 호출했을 때, 시스템에 저장된 최소한 5 개의 투표 질문이 콤마로 분리되어 발행일에 따라 출력된다

(3) template 생성

이제 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 사전형 객체를 세 번째 선택적 인수로 받는다

(3) view HTTP 예외 처리

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 예외를 발생시킨다

(4) URL namespace 추가

튜토리얼의 프로젝트는 polls라는 앱 하나만 가지고 진행했으나, 실제 Django 프로젝트는 앱이 여러 개일 수 있다
그렇기에 앱들의 url을 구분하기 위해서 URLconf에 namespace를 추가해야한다polls/urls.py 파일에 app_name을 추가하여 어플리케이션의 namespace를 설정할 수 있다


5. Django 앱 작성하기 part 4

(1) vote view 작성

이제 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 될 것이다

(2) result view 작성

index 뷰와 비슷하게 result 뷰와 템플릿을 작성해준다

polls/admin.py에 Choice 모델을 추가해주고
관리자 페이지에서 데이터를 추가해주었다

웹브라우저에서 '/polls/1/'로 접속하면 투표 페이지가 뜬다!

(3) generic view 사용하기

현재 index(), detail(), result() 뷰는 코드가 중복된다

이러한 뷰는 URL에서 전달 된 매개 변수에 따라 데이터베이스에서 데이터를 가져 오는 것과 템플릿을 로드하고 렌더링 된 템플릿을 리턴하는 기본 웹 개발의 일반적인 경우이다
Django는 이런 일반적인 경우를 위해 '제너릭 뷰'를 제공한다

이제 이 코드들을 제너릭 뷰로 리팩토링 해보겠다

먼저 polls/url.py에서 변수를 id값이 아닌 pk로 변경한다

이어서 view들을 위와 같이 수정해준다
view들을 함수가 아닌 class로 작성하여 각각 기능에 맞게 제너릭 뷰를 가져온다

  • IndexView:
    투표 목록을 보여주는 경우이므로 ListView로 리스트를 보여준다
  • model = Question:
    각각의 뷰들은 어떤 모델을 사용할지 알아야 하는데, 제너릭 뷰에서는 이런 속성이 model로 정의되어 있어 해당하는 모델을 'model = Question'를 통해 연결해준다
    하지만 IndexView에서는 model을 사용하지 않았는데, model을 사용하면 해당하는 모든 값을 가져오게 되기 때문에 전체가 아닌 일부만 가져오기 위함이다
    이를 위해 Question.objects.order_by('-pub_date')[:5]를 통해 원하는 데이터만 가져오는 함수 get_queryset()를 정의하였다

다시 정리하면, model을 통해 모델 이름을 명시하거나
모델의 일부 데이터만 필요한 경우 get_queryset 함수를 통해 일부만 가져온다
그리고 template_name에 연결하고자 하는 템플릿 html의 위치와 파일명을 지정해준다


여기까지 Django 튜토리얼을 따라해보았다
처음 해보는 거라 좀 헷갈리지만... 천천히 다시 읽어보면서 공부해야겠다!



참고: https://kitle.xyz/ez2django/

profile
핸수

0개의 댓글