본문 바로가기
Django

[Django] model, 마이그레이션, 템플릿

by 이농이능 2018. 1. 18.

프로젝트와 앱을 생성한 뒤,

앱에서 사용할 모델클래스를 앱의 models.py 파일에 정의해야 한다.



1. Django 모델


Django에서 Model은 데이타 서비스를 제공하는 Layer이다. Django의 Model은 각 Django App안에 기본적으로 생성되는 models.py 모듈 안에 정의하게 된다. models.py 모듈 안에 하나 이상의 모델 클래스를 정의할 수 있으며, 하나의 모델 클래스는 데이타베이스에서 하나의 테이블에 해당된다


모델 클래스는 models.Model 을 상속받아야 한다.

모델 클래스는 필드를 정의하기 위해 인스턴스 변수가 아닌 클래스 변수를 사용하는데, 이는 그 변수가 테이블 필드의 내용을 갖는 것이 아니라, 테이블의 컬럼 메타 데이타를 정의하는 것이기 때문이다. 필드를 정의하는 각각의 클래스 변수는 models.CharField(), models,IntegerField(), models.DateTimeField(), models.TextField() 등의 각 필드 타입에 맞는 Field 클래스 객체를 생성하여 할당한다. Field 클래스는 여러 종류가 있는데, 생성자 호출시 필요한 옵션들을 지정할 수 있다. 각 Field 클래스마다 반드시 지정해야 주어야 하는 옵션이 있을 수 있는데, 예를 들어 CharField (와 그 서브클래스들)은 필드의 최대 길이를 나타내는 max_length를 항상 지정해 주어야 한다.


모델 클래스 내부의 멤버 변수를 설정할 때는 FieldTypes를 참고해서 작성해야 한다. 


위와 같은 필드 타입 클래스 이외에, Django 프레임워크는 테이블 간 혹은 필드 간 관계(Relationship)을 표현하기 위해 ForeignKey, ManyToManyField, OneToOneField 클래스를 또한 제공하고 있다. 특히 ForeignKey는 모델 클래스간 (혹은 Underlying 테이블 간) Many-To-One (혹은 One-To-Many) 관계를 표현하기 위해 흔히 사용된다. 이 부분에 대한 보다 자세한 내용은 이 링크를 참조한다.




2. 마이그레이션과 DB


Django에서 Model 클래스를 생성하고 난 후, 해당 모델에 상응하는 테이블을 데이타베이스에서 생성할 수 있다. Python 모델 클래스의 수정 (및 생성 )을 DB에 적용하는 과정을 Migration이라 부른다. 이는 Django가 기본적으로 제공하는 ORM (Object-Relational Mapping) 서비스를 통해 진행된다.


sqlite3 이 장고는 기본적으로 지원하고 있다. 모델은 데이터베이스에서 하나의 테이블에 해당되는데 작성한 모델과 데이터베이스를 연결하기 위해서는 세팅이 필요하다 

- <프로젝트이름>/settings.py 에서 INSTALLED_APPS 리스트에 앱이름을 추가한다.

- <프로젝트이름> 폴더로 이동 후 python manage.py makemigrations 입력

 ㄴ> 모델 클래스로부터 테이블 스키마를 생성 혹은 수정하기 위함

- python manage.py migrate 입력 -> DB에 공간을 만들기 위함




* *SHELL - 직접 DB에 요청을 하는 다른 방법

shell 실행 방법

운영체제에 따라

    • windows - powershell에서
    • unix/linux - 터미널에서
    1. manage.py가 있는 폴더로 이동 후
    2. python manage.py shell

DB에 요청하기

1. 기본 - 사용할 모델 클래스 import

>>> from elections.models import Candidate

2. 모든 객체 불러오기 - all()

>>> Candidate.objects.all()

3. 새 객체 생성하고 저장하기 - Model.save()

>>> new_candidate = Candidate(name = "루비오") #생성만 한 상태. 아직 저장되지 않음
>>> new_candidate.save() #new_candidate가 DB에 저장됨

4. 특정 조건을 만족하는 객체 불러오기 - filter()

>>> no1 = Candidate.objects.filter(party_number = 1) #party_number = 1인 객체를 리스트 형태로 return
>>> no1[0].party_number #리스트 형태이기 때문에 index로 접근
>>> no1[0].name





 3. Django 템플릿


템플릿 추가하는 과정

    1. <앱이름> 폴더 아래에 templates 폴더 생성 
    2. templates 폴더 아래 <앱이름> 폴더 생성
    3. <앱이름> 폴더 아래 index.html 파일 생성 
    4. index.html 과 views.py 수정

Django에서의 View가 다른 MVC Framework에서의 Controller와 유사한 역활을 한다면, Django에서의 템플릿 (Template)은 MVC Framework에서의 View와 비슷한 역활을 한다. 템플릿 (Template)은 View로부터 전달된 데이타를 템플릿에 적용하여 Dynamic 한 웹페이지를 만드는데 사용된다.

 Django 개발 가이드라인은 "App폴더/templates/App명/템플릿파일" 처럼, 각 App 폴더 밑에 templates 서브폴더를 만들고 다시 그 안에 App명을 사용하여 서브폴더를 만든 후 템플릿 파일을 그 안에 넣기를 권장한다 (예: /home/templates/home/index.html ).



(1) 먼저 View (home/views.py)에서 다음과 같이 index()를 정의한다. 여기서 render는 django.shortcuts 패키지에 있는 함수로서 첫번째 파라미터로 request를, 그리고 두번째 파라미터로 템플릿을 받아들인다. 여기서 템플릿은 index.html으로 지정되어 있는데, 이는 home/templates/index.html을 가리키게 된다. 세번째 파라미터는 Optional 인데, View에서 템플릿에 전달한 데이타를 Dictionary로 전달한다. Dictionary의 Key는 템플릿에서 사용할 키(or 변수명)이고, Value는 전달하는 데이타의 내용을 담는다. 여기서는 message 라는 키로 "My Message"라는 문자열을 전달하고 있다.

1
2
3
4
5
from django.shortcuts import render
 
def index(request):
    msg = 'My Message'
    return render(request, 'index.html', {'message': msg})

(2) 다음으로 Template (home/templates/index.html)에 HTML 문서를 작성한다. 여기서 body 태그 안에 message를 보면 {{ }} 으로 둘러싸인 것을 볼 수 있는데, Django의 템플릿에서 {{ 변수명 }} 은 해당 변수의 값을 그 자리에 치환하라는 의미를 갖는다. Django Template은 또한 View로 부터 전달된 다양한 데이타들을 템플릿에 편리하게 넣을 수 있도록 여러 템플릿 태크( {% 탬플릿태그 %} 와 같은 형태, 아래 참조)들을 제공하고 있다.

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>{{message}}</h1>
</body>
</html>


** Django 템플릿 언어

변수

변수는 {{ 변수 }}와 같이 생겼습니다. 템플릿 엔진이 변수를 만나면, 평가하여 그 결과로 치환합니다. 변수명은 영문자와 밑줄("_")로 구성됩니다. 점(".")에는 특별한 의미가 있습니다. 중요한 점으로, 변수명에는 공백이나 특수문자를 사용할 수 없습니다.

점(.)은 변수의 속성에 접근할 때에 사용합니다.

필터

필터를 사용함으로써 변수의 표시에 변화를 줄 수 있습니다.

필터는 {{ name|lower }}와 같이 생겼습니다. 이것은 {{ name }} 변수에 lower 필터를 적용시켜서, 텍스트를 소문자로 변경시킨 결과를 표출합니다. 파이프(|)를 사용하여 필터를 적용합니다.

필터는 “연쇄적으로” 사용하여, 필터의 결과가 그 다음 필터에 적용되도록 할 수 있습니다.{{ text|escape|linebreaks }}는 텍스트 컨텐츠를 이스케이프한 다음, 행 바꿈을 <p> 태그로 바꾸기 위해 종종 사용되곤 합니다.

어떤 필터는 인자를 취합니다. 필터 인자는 {{bio|truncatewords:30 }}과 같이 사용합니다. 이것은 bio 변수의 처음 30 단어를 보여줍니다.

필터 인자에 공백이 포함된 경우에는 반드시 따옴표로 둘러싸야 합니다. 예를 들어 목록을 쉼표와 공백으로 join하는 경우 {{ list|join:", " }}과 같이 사용합니다.

일부의 예를 들었을 뿐이므로, 내장 필터 레퍼런스에서 전체 목록을 보시기 바랍니다.

템플릿 필터를 직접 만들 수도 있습니다. Custom template tags and filters를 읽어보세요.


태그

태그는 {% tag %}와 같이 생겼습니다. 태그는 변수에 비해 더 복잡합니다. 어떤 것은 텍스트를 생성하고, 어떤 것은 루프 또는 로직을 수행하며 외부적인 정보를 나중에 변수에 의해 사용될 템플릿에 적재합니다.

어떤 태그는 시작과 끝 태그를 필요로 합니다(예: {% tag %} ... 태그 내용 ... {% endtag %}).

Django에는 스무 개가 넘는 템플릿 태그가 내장되어 있습니다. 내장 태그 레퍼런스에서 읽어볼 수 있습니다. 어떤 것이 가능한지 맛보기를 위해, 자주 사용되는 태그의 예를 들어보겠습니다.


for
배열의 각 원소에 대하여 루프. 예를 들어, athlete_list에 들어 있는 선수의 목록을 출력하기 위하여 다음과 같이 할 수 있습니다.
<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>
if and else

변수를 평가하여, 변수가 “true”이면 블록의 컨텐츠를 표시:

{% if athlete_list %}
    Number of athletes: {{ athlete_list|length }}
{% else %}
    No athletes.
{% endif %}

위에서는, athlete_list가 비어있지 않다면, {{ athlete_list|length }} 변수에 의하여 선수의 숫자가 출력됩니다.

또한 if 태그 내에 필터 및 각종 연산자를 사용할 수 있습니다.

{% if athlete_list|length > 1 %}
   Team: {% for athlete in athlete_list %} ... {% endfor %}
{% else %}
   Athlete: {{ athlete_list.0.name }}
{% endif %}


템플릿 상속

Django의 템플릿 엔진에 있어서 가장 강력하고도 가장 복잡한 부분이 템플릿 상속입니다. 템플릿 상속을 통해 여러분의 사이트에서 공통적인 부분을 모두 갖고 있는 기초 “골격” 템플릿을 만들고 자식 템플릿이 덮어쓸 수 있는 **블록(block)**을 정의할 수 있도록 해줍니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}My amazing site{% endblock %}</title>
</head>

<body>
    <div id="sidebar">
        {% block sidebar %}
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/blog/">Blog</a></li>
        </ul>
        {% endblock %}
    </div>

    <div id="content">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

base.html이라고 부를 위의 템플릿은, 두 컬럼으로 된 페이지에 사용할 수 있는 간단한 HTML 골격 문서를 정의합니다. 비어있는 블록의 내용을 채우는 것은 “자식” 템플릿이 할 일입니다.


자식 템플릿은 다음과 같습니다.

{% extends "base.html" %}

{% block title %}My amazing blog{% endblock %}

{% block content %}
{% for entry in blog_entries %}
    <h2>{{ entry.title }}</h2>
    <p>{{ entry.body }}</p>
{% endfor %}
{% endblock %}

extends 태그가 핵심입니다. 템플릿 엔진에게 이 템플릿은 다른 템플릿을 “확장(extends)”한다고 알려줍니다. 템플릿 시스템이 이 템플릿을 평가할 때에는 부모를 – 이 경우, “base.html” –우선 찾습니다.

그때, 템플릿 엔진은 base.html에 있는 세 개의 block 태그를 알아차리고 자식 템플릿의 내용으로 치환합니다. 


HTML Escape

HTML 내용 중에 <, >, ', ", & 등과 같은 문자들이 있을 경우 이를 그 문자에 상응하는 HTML Entity로 변환해 주어야 하는데, Django 템플릿에서 이러한 작업을 자동으로 처리해 주기 위해 {% autoescape on %} 템플릿 태그나 escape 라는 필터를 사용한다.

예를 들어, 아래 예제에서 content 라는 변수에 인용부호가 들어 있다고 했을 때, 아래와 같이 autoescape 태그나 escape 필터를 사용해서 자동으로 변환하게 할 수 있다. 만약 이러한 변환을 하지 않으면 HTML이 중간에 깨지게 된다.

1
2
3
4
5
{% autoescape on %}     # autoescape 태그
    {{ content }}
{% endautoescape %}
 
{{ content|escape }}    # escape 필터

만약 이러한 HTML escape 혹은 HTML 인코딩 기능을 사용하지 않고, <, >, ', ", & 이 들어간 문자열을 HTML에서 사용하고자 한다면, 각 문자를 HTML Entity로 미리 변환해 주어야 한다. 이러한 변환을 보다 편리하게 하는 한 방법으로 온라인 HTML 인코딩 변환 도구를 사용할 수 있다.


출처 : 

https://programmers.co.kr/learn/courses/6

http://pythonstudy.xyz/python/article/308-Django-%EB%AA%A8%EB%8D%B8-Model

https://django-doc-test-kor.readthedocs.io/en/old_master/topics/templates.html