TIL 41. django 공식문서 따라치기

rahula·2021년 6월 16일
0

django

목록 보기
2/5
post-thumbnail

django로 첫번째 앱 만들기를 해보며 배운 점들을 기록합니다. 이 글은 공식문서와 책 점프투장고를 토대로 썼습니다.

django 첫번째 앱 만들기

프로젝트 생성

$ django-admin startproject 프로젝트이름

startproject 명령어는 django가 웹서버 개발에 필수적인 파일구조를 만들도록 한다.

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        asgi.py
        wsgi.py

directory 구조

더 자세하게 살펴보자.

mysite/는 루트 direcotry로, 프로젝트 전체를 담는 컨테이너라고 할 수 있다.

mysite/ 디렉토리 내부에는 프로젝트를 위한 실제 Python 패키지들이 저장됩니다. 이 디렉토리 내의 이름을 이용하여, (mysite.urls 와 같은 식으로) 프로젝트의 어디서나 Python 패키지들을 임포트할 수 있습니다.

한 마디로, mysite프로젝트 내에서 무언가를 절대경로로 import할 때 기준으로 잡는 directory가 되는 것.

django-admin과 manage.py의 차이점

manage.py는 django 프로젝트와 상호작용하는 명령어의 모음이다.

django-admin은 django 자체에 대해서 관리자로써 일을 할 때 쓰는 명령어이다. 반면 manage.py는 특정 프로젝트에 관련된 일을 할 때 쓰는 명령어다.

mysite/__init__.py: Python으로 하여금 이 디렉토리를 패키지처럼 다루라고 알려주는 용도의 단순한 빈 파일입니다. Python 초심자라면, Python 공식 홈페이지의 패키지를 읽어보세요.

mysite/settings.py: 현재 Django 프로젝트의 환경 및 구성을 저장합니다. Django settings에서 환경 설정이 어떻게 동작하는지 확인할 수 있습니다.

mysite/urls.py: 현재 Django project 의 URL 선언을 저장합니다. Django 로 작성된 사이트의 《목차》 라고 할 수 있습니다. URLconf를 하는데 있어서 필수적이다.

서버 시작하기

python manage.py runserver : 해당 directory, 즉 프로젝트에서 서버를 시작. runserver명령어 뒤에 포트번호를 붙여주면 기본 포트번호인 8000이 아닌 다른 포트번호로 서버를 열 수 있다.

앱 생성

Django에서 당신이 작성하는 각 어플리케이션들은 다음과 같은 관례로 Python 패키지가 구성됩니다. Django 는 앱(app) 의 기본 디렉토리 구조를 자동으로 생성할 수 있는 도구를 제공하기 때문에, 코드에만 더욱 집중할 수 있습니다.

프로젝트와 앱의 차이점?

앱은 어떤 기능을 하는 하나의 웹애플리케이션이라고 할 수 있다. 이와 달리 프로젝트는 특ㄱ정 웹사이트를 위해 만든 앱과 설정의 집합이다. 한 프로젝트는 여러개의 앱을 담고 있을 수 있고, 하나의 앱은 여러개의 프로젝트에 들어갈 수 있다.

python manage.py startapp polls

뷰 작성과 URLconf

클라이언트에서 요청을 할때, django는 url을 구분하고 각각의 url마다 다른 응답결과를 주기 위해서 URLconf와 view를 사용한다. 그리고 요청한대로 해당 페이지를 가져오는 URL매핑이 있는지 urls.py파일을 뒤져 찾아본다.

어떤 url로 요청이 들어오면 URLconf에서는 특정 함수를 호출하는데, 이게 view.py파일의 함수들이다.

뷰를 호출하려면 이와 연결된 URL 이 있어야 하는데, 이를 위해 URLconf가 사용됩니다.

  1. 앱의 디렉토리에서 URLconf를 생성하려면, urls.py라는 파일을 생성해야 한다.
from django.urls import path

from . import views

urlpatterns = [
    path('', views.index, name='index'),
]
  1. 최상위 URLconf에서 해당 앱의 URLconf를 바라보게 설정해야 한다.

urlpatterns 리스트에 include() 함수를 다음과 같이 추가합니다.

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
    path('admin/', admin.site.urls),
]

urlpatterns변수를 보면 polls/와 그에 대한 view를 매핑시켰다.

django는 url을 어떻게 매칭시킬까?

ROOT_URLCONF설정에 의해 해당 모듈을 바라보도록 지정되어 있기 때문에, mysite.urls모듈을 불러온다. urlpatterns라는 변수를 찾고, 순서대로 패턴을 따라간다. app/을 찾은 후엔, 34/urlconf로 전달하는 식.
views함수에선 path와 일치한다면, 함수가 호출되는 식이다.

호스트명과 포트번호는?

호스트명과 포트번호는 django가 실행되는 환경에 따라 변하는 값이며 django가 이미 알고 있는 값이다. 그러므로 urlpatterns에는 호스트명과 포트번호를 입력하지 않는다.

슬래시 (/)

슬래시를 붙이면 사용자가 슬래시 없이 주소를 입력해도 django가 자동으로 슬래시를 붙여준다. url을 정규화하는 django의 기능 덕분.

BASE_DIR

프로젝트 directory는 settings.py의 BASE_DIR변수에 저장되어 있다. django는 이 경로를 기본경로로 인식하고, 우리는 매번 기본경로를 붙여주지 않아도 된다.

include함수

다른 URLconf를 참조할 수 있게 해주는 함수. django가 include함수를 만나면, url의 그 시점까지 일치하는 부분은 잘라내고, 남는 string을 포함했던 URLconf를 쉽게 연결할 수 있다.

include('polls.urls')polls로 시작되는 페이지 요청은 모두 polls/urls 파일에 있는 URL매핑을 참고하여 처리하라는 의미다.
include함수가 필요하지 않는경우는 django가 기본으로 제공하는 admin페이지인 admin.site.urls가 유일하다.

path함수와 인수들

path() 함수에는 2개의 필수 인수인 route 와 view, 2개의 선택 가능한 인수로 kwargs 와 name 까지 모두 4개의 인수가 전달된다.

route

URL 패턴을 가진 문자열. 요청이 처리될 때, Django 는 urlpatterns 의 첫 번째 패턴부터 시작하여, 일치하는 패턴을 찾을 때 까지 요청된 URL 을 각 패턴과 리스트의 순서대로 비교합니다. 패턴들은 GET 이나 POST 의 매개 변수들, 혹은 도메인 이름을 검색하지 않습니다. URLconf는 앱의 이름인 /polls/ 부분만 신경쓴다.

view

Django 에서 일치하는 패턴을 찾으면, HttpRequest 객체를 첫번째 인수로 하고, 경로로 부터 〈캡처된〉 값을 키워드 인수로하여 특정한 view 함수를 호출한다.

kwargs

임의의 키워드 인수들은 목표한 view 에 사전형으로 전달됩니다.

name

URL 에 이름을 지으면, 템플릿을 포함한 Django 어디에서나 명확하게 참조할 수 있습니다. 이 강력한 기능을 이용하여, 단 하나의 파일만 수정해도 project 내의 모든 URL 패턴을 바꿀 수 있도록 도와줍니다.

Model 생성

기본 어플리케이션들 중 몇몇은 최소한 하나 이상의 데이터베이스 테이블을 사용하는데, 그러기 위해서는 데이터베이스에서 테이블을 미리 만들 필요가 있습니다.

python manage.py migrate

migrate 명령어는 INSTALLED_APPS의 설정을 살펴본 다음, settting.py파일의 설정에 따라서 필수적인 DB 테이블을 생성한다. 그러면 DB migration은 app과 동일하게 된다.

from django.db import models

# models : 부가적인 메타데이터를 가진 DB의 구조

# Question : 질문에 대한 모델. models.Model에게 상속받은 자식 Class이다.
# ? : 뭘 상속받는다는거?
class Question(models.Model):
    # models.Charfield : string값 데이터라는 것을 나타내고, max_length인자값을 필수로 받는다.
    question_text = models.CharField(max_length=200)
    # models.DateTImeField : 시간 데이터라는 것을 나타낸다. settings.py의 TIME_ZONE에 담긴 값이 여기서 적용되는거 아닐까?
    pub_date = models.DateTimeField('date published!')

# Choice : 선택지에 대한 모델. 마찬가지로 models.Model에게 상속받은 class.
class Choice(models.Model):
    # ForeignKey : 각각의 Choice가 하나의 Question에 관계되도록.
    # ? : on_delete인자는 뭐지?
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    # choice_text : 선택지의 텍스트.
    choice_text = models.CharField(max_length=200)
    # models.IntegerField : integer 데이터타입이라는 것. 
    votes = models.IntegerField(default=0)

Model 이란?

본질적으로, 모델이란 부가적인 메타데이터를 가진 데이터베이스의 구조(layout)다. 모델은 데이터 에 관한 단 하나의, 가장 확실한 진리의 원천입니다. 이것은 당신이 저장하는 데이터의 필수적인 필드들과 동작들을 포함하고 있습니다.

설문조사 사이트를 만들것이기 때문에, 나에겐 2가지 Model이 필요하다. QuestionChoice이다. Question은 question_text변수와 publication date 변수를 갖는다. Choice는 선택에 대한 text와 총 투표수를 담고 있다. 각각의 Choice는 Question과 연결된다.

each model is represented by a class that subclasses django.db.models.Model.

각각의 Model들은 django가 제공하는 models.Model에게서 종속받는다.

Field

각각의 Field 인스턴스의 이름(question_text 또는 pub_date)은 기계가 읽기 좋은 형식(machine-friendly format)의 데이터베이스 필드 이름이다.

몇몇 Field 클래스들은 필수 인수가 필요합니다. 예를 들어, CharField 의 경우 max_length 를 입력해 주어야 한다.

또한 Field 는 다양한 선택적 인수들을 가질 수 있습니다. 이 예제에서는, default 로 하여금 votes 의 기본값을 0 으로 설정하였습니다.

마지막으로, ForeignKey 를 사용한 관계설정에 대해 설명하겠습니다. 이 예제에서는 각각의 Choice 가 하나의 Question 에 관계된다는 것을 Django 에게 알려줍니다. Django 는 다-대-일(many-to-one), 다-대-다(many-to-many), 일-대-일(one-to-one)과 같은 모든 일반 데이터베이스의 관계들를 지원합니다.

모델의 활성화

모델들에 대한 이 작은 코드가, Django에게는 상당한 양의 정보를 전달합니다. Django는 이 정보를 가지고 다음과 같은 일을 할 수 있습니다.

  1. 이 앱을 위한 데이터베이스 스키마 생성(CREATE TABLE 문)
  2. Question과 Choice 객체에 접근하기 위한 Python 데이터베이스 접근 API를 생성

그러나, 가장 먼저 현재 프로젝트에게 polls 앱이 설치되어 있다는 것을 알려야 합니다.

from django.apps import AppConfig

# apps 파일 : 앱의 구성 클래스에 대한 정보!
# django.apps.AppConfig에게 상속받은 클래스. 이름은 처음 app을 시작할 때 django에서 지어주는 듯? 
class PollsConfig(AppConfig):
    # ? : default_auto_field
    default_auto_field = 'django.db.models.BigAutoField'
    # ? : name
    name = 'polls'

앱을 현재의 프로젝트에 포함시키기 위해서는, 앱의 구성 클래스에 대한 참조를 INSTALLED_APPS 설정에 추가해야 한다. mysite/settings.py 파일을 편집하여 INSTALLED_APPS 설정에 추가하면 된다.

INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    ...

makemigration

python manage.py makemigrations polls

makemigrations 을 실행시킴으로서, 당신이 모델을 변경시킨 사실과(이 경우에는 새로운 모델을 만들었습니다) 이 변경사항을 migration으로 저장시키고 싶다는 것을 Django에게 알려줍니다.

migration은 데이터들의 변화를 django가 모델들(그리고 DB schema)에 저장하는 방법이다.

polls/migrations/0001_initial.py 파일을 보면 Migration이 어떻게 이루어지는 지를 볼 수 있다.

migration이 어떤 SQL문을 실행하는가?

python manage.py sqlmigrate polls 0001

Create model, Create TABLE과 각 테이블에 대한 속성을 넣는 SQL문을 대신 실행해주고 있었다.

자세히 살펴보자.
1. Create model :
2. CREATE TABLE "polls_question" : 테이블 이름은 앱의 이름과 모델의 이름(소문자)이 조합되어 자동으로 생성된다.
3. "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT : django는 migration 시 기본 키(ID)를 자동으로 추가한다. id 필드를 생성하고, 그 뒤에는 필드의 속성을 적는다. integer 타입으로 하고, null값이 되어서는 안되며, primary key이고, 데이터가 쌓이면 자동증가가 된다는 뜻인 것 같다.
4. "question_id" bigint NOT NULL REFERENCES "polls_question" : 관례에 따라, Django는 foreign key 필드명에 "_id" 이름을 자동으로 추가합니다. REFERENCES는 polls_question, 즉 Question 모델을 참조한다는 의미다.

migrate

python manage.py migrate

migrate 명령은 아직 적용되지 않은 마이그레이션을 모두 수집해 이를 실행하며(Django는 django_migrations 테이블을 두어 마이그레이션 적용 여부를 추적합니다) 이 과정을 통해 모델에서의 변경 사항들과 데이터베이스의 스키마의 동기화가 이루어집니다.
마이그레이션은 매우 기능이 강력하여, 마치 프로젝트를 개발할 때처럼 데이터베이스나 테이블에 손대지 않고도 모델의 반복적인 변경을 가능하게 해줍니다. 동작 중인 데이터베이스를 자료 손실 없이 업그레이드 하는 데 최적화 되어 있습니다.

모델을 수정하고 migrate하는 방법 요약 :
1. (models.py 에서) 모델을 변경합니다.
2. python manage.py makemigrations을 통해 이 변경사항에 대한 마이그레이션을 만드세요.
3. python manage.py migrate 명령을 통해 변경사항을 데이터베이스에 적용하세요.

모델의 instance 생성

  1. 모델 import : polls.models에서 Choice, Question모델을 import
  2. instance 목록 보기 : Question.objects.all함수로 클래스에 대한 instance객체 목록을 볼 수 있다.
  3. 모델의 instance 생성 : Question()의 인자값으로 models.py에서 정의한대로 question_text와 pub_date인자값을 준다.
  4. save : 무슨 뜻인지는 모르겠지만 일단 저장한다는 것같다.

여기서 잠깐. <Question: Question object (1)>은 이 객체를 표현하는 데 별로 도움이 되지 않습니다. (polls/models.py 파일의) Question 모델을 수정하여, __str__() 메소드를 Question과 Choice에 추가해 봅시다.

def __str__(self):
        return self.question_text

__str__() 메소드를 추가하는것은 객체의 표현을 대화식 프롬프트에서 편하게 보려는 이유 말고도, Django 가 자동으로 생성하는 관리 사이트 에서도 객체의 표현이 사용되기 때문입니다.

DJango 관리자

Django는 모델에 대한 관리용 인터페이스를 모두 자동으로 생성합니다. 관리자 사이트는 사이트 방문자를 위한 것이 아니라, 사이트 관리자를 위한 것입니다.

관리자 사이트의 기본 구조는 django.contrib.auth에서 제공된다.

관리자 사이트에서 앱을 변경할 수 있게 하기

admin.site.register함수를 이용해서 인자값으로 내가 넣고 싶은 모델을 넣어줘야 한다.

이 서식은 Question 모델에서 자동으로 생성되었습니다. 모델의 각 필드 유형들은 (DateTimeField, CharField) 적절한 HTML 입력 위젯으로 표현됩니다. 필드의 각 유형들은 Django 관리 사이트에서 어떻게 표현해되어야 할지 알고 있습니다.

필드는 DB 테이블의 각 column을 말한다. Field

View 추가하기

여기서 만들고 싶은 페이지는 index, detail, result, vote 총 4개다. 따라서 views.py에서는 함수를 4개 만들어야 하고, urls.py에서 각각의 url에 대해서 views.py의 함수를 인자값을 넣어야 한다.

사용자가 웹사이트의 페이지를 요청할 때 Django는 mysite.urls 파이썬 모듈을 불러오게 됩니다. mysite.urls에서 urlpatterns라는 변수를 찾고, 순서대로 패턴을 따라갑니다. 'polls/'를 찾은 후엔, 일치하는 텍스트("polls/")를 버리고, 남은 텍스트인 "34/"를 〈polls.urls〉 URLconf로 전달하여 남은 처리를 진행합니다. 거기에 '<int:question_id>/'와 일치하여, 결과적으로 detail() 뷰 함수가 호출됩니다.

View가 실제로 뭔가를 하도록 하기

각 뷰는 두 가지 중 하나를 하도록 되어 있습니다. 요청된 페이지의 내용이 담긴 HttpResponse 객체를 반환하거나, 혹은 Http404 같은 예외를 발생하게 해야합니다.

from django.http import HttpResponse

from .models import Question


def index(request):
    latest_question_list = Question.objects.order_by('-pub_date')[:5]
    output = ', '.join([q.question_text for q in latest_question_list])
    return HttpResponse(output)

HttpResponse함수의 인자값으로 보내진 데이터를 응답결과로써 보낸다. HttpRespionse는 페이지 요청에 대한 응답을 할 때 사용하는 django의 class이다. 또한 함수가 받는 매개변수 request는 django에 의해 자동으로 전달되는 HTTP요청을 의미한다.
에러를 발생시키려면 Http404함수를 사용한다.
HttpResponseRedirect함수는 응답을 보내는 동시에 다른 페이지로 url을 재전송한다.

템플릿 생성

{% if latest_question_list %}
    <ul>
    {% for question in latest_question_list %}
        <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No polls are available.</p>
{% endif %}

template 불러오고 context전달하기

django.template.loader 객체는 html template을 불러온 후, context를 전달하는 역할을 한다.

template name spacing

django는 같은 이름의 template을 보면 걍 가장 먼저 본 걸 인식한다. 그래서 구별을 시키려면, template 파일들을 서로 다른 directory에 넣어야 한다.

Cross Site Request Forgeries

CSRF는 django에서 템플릿을 만들 때 필요한 보안사항이다. 따라서 템플릿을 만들지 않는다면 CSRF사항은 추가하지 않아도 된다.

CORS headers

대신 django는 CORS를 필수적으로 넣어줘야 한다.

추가 질문

  1. django-admin은 또 어떤 기능이 있을까? 구체적으로 알고 싶다.
  2. django.http모듈이 갖고 있는 객체를 더 알고 싶다. HttpRequest도 있었는데, 이건 한 서버에서 다른 서버로 요청을 보낼 수 있다는 건가?
  3. urlpatterns는 정해진 변수명인가? django는 어떤 과정으로 url패턴을 인식하는가?
  4. path함수는 구체적으로 뭘 return할까?
  5. django.db.models.Model에서 뭘 종속받는가?
  6. 기계가 읽기 좋은 형식(machine-friendly format)의 이름이란?
  7. django 쉘에서 나오는 Queryset과 save함수
  8. migration자체가 ORM인건가?
  9. django 관리자 쓰는 법
  10. raise 키워드. 에러를 내뱉는 방법.
  11. 약결합(loose coupling)이 뭐지? django의 중요한 설계목표라는데.
  12. 서버의 경쟁상태란? Avoiding race conditions using F()
  13. generic view와 generic
  14. 프로젝트에서 이 지식들이 어떻게 쓰일까!
profile
백엔드 지망 대학생

0개의 댓글