TIL10: django-2

Seoyul Kim·2020년 4월 5일
1

Django

목록 보기
2/12
post-custom-banner

django project

  • 장고에서 새로운 웹 프로젝트를 만들기 위해서는 django-admin.py라는 django 관리자 모듈을 사용한다.
  • 가상환경을 활성화 하고 프로젝트를 만들 디렉토리로 이동한 후 아래 명령어를 실행하여 새 프로젝트를 생성한다.
django-admin startproject '프로젝트명'
  • 위 명령어는 새 프로젝트를 '프로젝트명' 이라는 서브 폴더에 생성하고 그 안에 몇개의 파일들을 생성한다.
  • manage.py 는 웹프로젝트를 개발, 관리하는데 필요한 여러 기능을 제공하고, urls.py는 URL 매핑을 위한 파일이다.

django 서버 실행

  • 웹프로젝트로 부터 웹 서비스를 시작하기 위해서는 아래의 명령을 실행하고
python manage.py runserver

django developement server가 시작되면 메세지가 출력되며 메세지 중간에 웹 서비스의 url주소를( http://127.0.0.1:8000 ) 찾을 수 있다.

  • 웹 브라우저에서 이 url 주소로 접속하면 웹페이지를 볼 수 있는데 이때 웹 브라우저에 표시되는 웹페이지는 django 프레임 워크에서 디폴트로 보여주는 웹페이지이다.

django app

  • django app은 장고에서 사용하는 파이썬 패키지이다. django app 패키지는 안에 자신의 모델 뷰 템플릿 url 매핑 등을 독자적으로 가지고 있으며 일반적으로 하나의 장고 프로젝트는 하나 이상의 장고 app으로 구성되어 있다.
  • 규모가 큰 장고 프로젝트는 보통 여러개의 django app들을 모듈화 하여 구성하는데 모듈화된 app들고 구성하며면 개발 및 유지 보수가 효율적이기 때문이다. 또한 잘 모듈화 된 app은 여러 웹 프로젝트에서 쉽게 재사용 할 수 있다.
  • 하나의 django app을 생성하기 위해서는
python manage.py startapp 'app이름' #을 실행한다
  • 위 명령을 실행하면 app이름의 서브 폴더가 생성되고 그 안에 django app에 필요한 기본 파일들이 생성된다.

1. django view

  • 필요한 데이터를 모델에서 가져와서 적절히 가공하여 웹 페이지 결과를 만들도록 컨트롤한다.
  • 일반적으로 django에서는 좀 더 복잡한 html을 처리하기 위해 뷰 템플릿을 사용한다
  • MTV 패턴
    django는 model template view라는 MTV패턴을 따르고 있다.
    MTV는 MVC(model view controller)와 유사한데 장고는 컨트롤러 역활을 장고 프레임워크 자체에서 한다고 본다.
  • 모델은 데이터를 표현하는데 사용되며 하나의 모델클래스는 디비에서 하나의 테이블로 표현된다.
  • 뷰는 request를 받아 response를 리턴하는 컴포넌트로서 모델로부터 데이터를 읽거나 저장할 수 이씅며 template을 호출하여 데이터를 ui상에 표현하도록 할 수 있다.
  • 템플릿은 presentation logic만을 갖는데 html 을 생성하는 것을 목적으로 하는 컴포넌트이다.

2. django template

  • 뷰로부터 전달된 데이터를 템플릿에 적용하여 다이나믹한 웹페이지를 만든다.

    • app template 폴더 만들 때 주의사항
      app폴더 밑에 템플릿 서브 폴더를 만들고 다시 그 안에 app명을 사용하여 서브폴더를 만든 후 템플릿 파일을 그 안에 넣기를 권장한다.
      만약 복수의 앱들이 동일한 템플릿을 가진 경우 뷰에서 잘못된 템플릿을 가져올 수 있다.
      템플릿을 찾을 때 자신의 앱 내의 템플릿을 먼저 찾는것이 아니라 전체 앱들의 템플릿 폴더들을 처음부터 순서대로 찾기 때문이다.
  • 템플릿을 html로만 쓰여진 static html 파일일 수 있지만 거의 대부분의 경우 뷰로부터 어떤 데이터를 전달받아 html템플릿 안에 그 데이터를 동적으로 치환해서 사용한다.

  • ex) index 뷰에서 message 라는 데이타를 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"라는 문자열을 전달하고 있다.

def index(request):
  msg = 'My Message'
  return render(request, 'home/index.html', {'message': msg}

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>{{message}}</h1>
</body>
</htmㅣ>

템플릿 언어

템플릿 변수

{{변수}}
  • {{ 와 }} 로 둘러싸여 있는 변수로 그 변수의 값이 해당 위치에 치환된다.

템플릿 태그

  • {% 와 %}로 둘러싸여 있고 이 태그 안에는 if for 루프같은 flow control 문장에서부터 웹컨트롤 처럼 내부 처리 결과를 직접 덤프하는 등 여러 용도로 쓰일 수 있다.
    템플릿 필터

템플릿 필터는 변수의 값을 특정한 포맷으로 변형하는 기능을 한다. 예를 들어, 날짜를 특정 날짜 포맷으로 변경하거나 문자열을 대소문자로 변경하는 일등을 할 수 있다.

날짜 포맷 지정

{{ createDate|date:"Y-m-d" }}
  • 소문자로 변경
{{ lastName|lower }}

코멘트

  • 템플릿에서 코멘트를 넣는 방법은 크게 2가지이다. 한 라인에 코멘트를 적용할 때는 코멘트를 {# 과 #} 으로 둘러싸면 된다. 또한, 복수 라인 문장을 코멘트할 경우는 문장들을 {% comment %} 태그와 {% endcomment %}로 둘러싸면 된다.
{# 1 라인 코멘트 #}
 
{% comment %}  
  <div>
      <p>
          불필요한 블럭
      </p>
      <span></span>
  </div>
{% endcomment %}

HTML Escape

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

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

{% autoescape on %}     # autoescape 태그
    {{ content }}
{% endautoescape %}
 
{{ content|escape }}    # escape 필터

3. django model

  • Django 모델은 "django.db.models.Model" 의 파생 클래스이며, 모델의 필드는 클래스의 Attribute로 표현되며 테이블의 컬럼에 해당한다.
  • 모델 클래스는 필드를 정의하기 위해 인스턴스 변수가 아닌 클래스 변수를 사용하는데, 이는 그 변수가 테이블 컬럼의 내용을 갖는 것이 아니라, 테이블의 컬럼 메타 데이타를 정의하는 것이기 때문이다.
  • 필드를 정의하는 각각의 클래스 변수는 models.CharField(), models,IntegerField(), models.DateTimeField(), models.TextField() 등의 각 필드 타입에 맞는 Field 클래스 객체를 생성하여 할당한다.

Field Type

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

foreign key(외래키)

  • 두 테이블을 서로 연결하는데 사용되는 키이며 외래키가 포함된 테이블을 자식 테이블이라고 하고 외래키 값을 제공하는 테이블을 부모 테이블이라고 한다.

외래키 주의사항

  1. 외래키값을 null 이거나 부모테이블의 기본키 값과 동일해야 한다.
  2. 부모 테이블의 기본키, 고유키를 외래키로 지정할 수 있다.
  3. 외래키는 부모테이블이 기본 키 개수만큼 지정할 수 있다.
  4. 외래키로 지정할 두 테이블의 필드는 같은 데이터 타입이어야 한다.
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)

외래키 옵션

1) On Delete
Cascade : 부모 데이터 삭제 시 자식 데이터도 삭제 
Set null : 부모 데이터 삭제 시 자식 테이블의 참조 컬럼을 Null로 업데이트
Set default : 부모 데이터 삭제 시 자식 테이블의 참조 컬럼을 Default 값으로 업데이트
Restrict : 자식 테이블이 참조하고 있을 경우, 데이터 삭제 불가
No Action : Restrict와 동일, 옵션을 지정하지 않았을 경우 자동으로 선택된다.

2) On Update
Cascade : 부모 데이터 업데이트 시 자식 데이터도 업데이트 
Set null : 부모 데이터 업데이트 시 자식 테이블의 참조 컬럼을 Null로 업데이트
Set default : 부모 데이터 업데이트 시 자식 테이블의 참조 컬럼을 Default 값으로 업데이트
Restrict : 자식 테이블이 참조하고 있을 경우, 업데이트 불가
No Action : Restrict와 동일, 옵션을 지정하지 않았을 경우 자동으로 선택된다.


foriegnkey 출처
https://bamdule.tistory.com/45


4. DB Migration

  • 장고에서 모델 클래스를 생성하고 난 후 해당 모델에 상응하는 테이블을 데이터베이스에서 생성할 수 있다.
  • 파이썬 모델클래스의 수정 및 생성을 DB에 적용하는 과정을 migration이라고 부른다.
  • 이는 장고가 기본적으로 제공하는 ORM(object relational mapping)서비스를 통해 진행된다.
  • 장고 모델 클래스로부터 테이블을 생성하기 위해서는 크게 migration을 준비하는 과정과 이를 적용하는 과정으로 나뉘는데 다음과 같은 절차를 따른다.

1.settings.py 파일 안의 INSTALLED_APPS 리스트에 (만약 이미 추가되지 않았다면) 해당 Django App을 추가한다.

  1. 모델 클래스로부터 테이블 스키마를 생성 혹은 수정하기 위하여 아래 명령을 실행한다. 이 명령이 실행되면 해당 Django App 안에 migrations 라는 서브폴더를 만들고 테이블 생성 및 수정을 위한 파이썬 마이크레이션 파일들을 생성한다.
$ ./manage.py makemigrations
  1. 모델 클래스로부터 실제 DB에 테이블을 생성하거나 수정하기 위해 아래 명령을 실행한다. 이는 실제 Migration을 DB에 적용하는 명령이다.
$ ./manage.py migrate
  • Migration에 의해 생성되는 테이블은 "App명_ModelClass명"의 형식으로 생성된다.

DB 관리 Shell

  • 데이타베이스 관리를 위해 "manage.py dbshell" 명령을 사용할 수 있다. Migration이 완료되면 dbshell 을 사용하여 생성된 테이블과 테이블의 컬럼 정보, 혹은 테이블 내용 등을 확인할 수 있다.
$ ./manage.py dbshell

5. django model API

  • 모델클래스를 정의하게 되면 장고는 데이터를 추가/갱신하고 읽어들일 수 있는 다양한 데이터베이스 API드을 자동으로 제공한다. ORM서비스를 기본적으로 제공함에 따른것으로 데이터베이스를 편리하게 핸들링 할 수 있게 도와준다

Insert

  • 데이터를 삽입하기 위해서는 먼저 테이블에 해당하는 모델클래스로부터 객체를 생성하고 그 객체의 save()메서드를 호출하면 된다.
  • save() 메서드가 호출되면, SQL의 INSERT이 생성되고 실행되어 테이블에 데이타가 추가된다.
class MainView(View):
  def post(self, request):
    data = json.loads(request.body)
    Users(
      name = data['name'],
      email = data['email'],
      password = data['password']
    ).save()

    return JsonResponse({'message':'SUCCESS'}, status=200)

Select

  • Django는 디폴트로 모든 Django 모델 클래스에 대해 "objects" 라는 Manager (django.db.models.Manager) 객체를 자동으로 추가한다.
  • Django 에서 제공하는 이 Manager를 통해 특정 데이타를 필터링할 수도 있고 정렬할 수도 있으며 기타 여러 기능들을 사용할 수 있다.
  • 데이타를 읽어오기 위해서는 Django 모델의 Manager 즉 "모델클래스.objects" 를 사용한다. (객체명이 아니라 클래스명을 사용함에 주의).

query method

  • Django Model API에는 기본적으로 제공하는 여러 쿼리 메서드들이 있다.
  • all() : 테이블 데이타를 전부 가져오기 위해서는 Feedback.objects.all() 과 같이 all() 메서드를 사용한다. 다음은 Feedback 테이블의 모든 데이타의 id와 name 컬럼을 출력하는 예이다.
for f in Feedback.objects.all():
    s += str(f.id) + ' : ' + f.name + '\n'

get()과 같이 단일 행의 결과가 존재하지 않을 경우 모델명.DoesNotExist의 exception으로 처리되지만 all()과 같은 여러 행이 나오는 경우엔 exception이 아닌 빈 값으로 처리된다.

  • get() : 하나의 Row만을 가져오기 위해서는 get() 메서드를 사용한다. 예를 들어, 아래는 Primary Key (일반적으로 id 컬럼)가 1인 row를 가져온다.
    타입이 Query Set이 아닌 단일행으로 나온다.
row = Feedback.objects.get(pk=1)
print(row.name)

filter() : 특정 조건에 맞는 Row들을 가져오기 위해서는 filter() 메서드를 사용한다. 예를 들어, 아래는 name 필드가 Kim 인 데이타만 가져온다.

rows = Feedback.objects.filter(name='Kim')
  • exclude() : 특정 조건을 제외한 나머지 Row들을 가져오기 위해서는 exclude() 메서드를 사용한다. 예를 들어, 아래는 name 필드가 Kim이 아닌 데이타만 가져온다.
rows = Feedback.objects.exclude(name='Kim')
  • count() : 데이타의 갯수(row 수)를 세기 위해 count() 메서드를 사용한다.
n = Feedback.objects.count()
  • order_by() : 데이타를 키에 따라 정렬하기 위해 order_by() 메서드를 사용한다. order_by() 안에는 정렬 키를 나열할 수 있는데, 앞에 -가 붙으면 내림차순이다. 아래는 id를 기준으로 올림차순, createDate로 내림차순으로 정렬하게 된다.
rows = Feedback.objects.order_by('id', '-createData')
  • distinct() : 중복된 값은 하나로만 표시하기 위해 distinct() 메서드를 사용한다. 아래는 name필드가 중복되는 경우 한번만 표시하게 된다.
rows = Feedback.objects.distinct('name')
  • first() : 데이타들 중 처음에 있는 row만을 리턴한다. 아래는 name필드로 정렬했을 때 처음 row를 리턴한다.
rows = Feedback.objects.order_by('name').first()
  • last() : 데이타들 중 마지막에 있는 row만을 리턴한다. 아래는 name필드로 정렬했을 때 마지막 row를 리턴한다.
rows = Feedback.objects.order_by('name').last()
  • 쿼리 메서드들은 하나 하나가 실제 데이타 결과를 직접 리턴한다기 보다는 쿼리 표현식(Django에서 QuerySet이라 한다)을 리턴하는데, 여러 메서드들을 체인처럼 연결하여 사용할 수 있다.
  • 여러 체인으로 연결되어 리턴된 쿼리가 해석되어 DB에 실제 하나의 쿼리를 보내게 된다. 아래는 여러 메서드들을 사용하여 체인으로 연결한 예제이다.
row = Feedback.objects.filter(name='Kim').order_by('-id').first()

Update

  • 데이터를 수정하기 위해서는 먼저 수정할 Row 객체를 얻은 후 변경할 필드들을 수정한다. 이어 마지막에 save() 메서드를 호출되면, SQL의 UPDATE이 실행되어 테이블에 데이타가 갱신된다. 아래는 id가 1인 Feedback 객체에 이름을 변경하는 코드이다.
fb = Feedback.objects.get(pk=1)
fb.name = 'Park'
fb.save()

Delete

  • 데이터를 삭제하기 위해서는 먼저 삭제할 Row 객체를 얻은 후 delete() 메서드를 호출하면 된다. 아래는 id가 2인 Feedback 객체를 삭제하는 코드이다.
fb = Feedback.objects.get(pk=2)
fb.delete()

6. django app URL mapping

path() 함수

  • django.urls.path() 함수는 path(route, view, kwargs=None, name=None) 와 같이 4개의 파라미터를 받아들일 수 있는데, 처음 2개의 파라미터는 반드시 있어야 하고, 뒤의 2개는 옵션이다.
  • 첫번째 파라미터에는 URL route에서 사용된 경로를 지정하는 것이고, 두번째 파라미터는 해당 URL에 상응하는 View를 지정하는 것이다.
  • 두번째 파라미터에서 View를 지정하는 방식으로는 함수 뷰(function view)의 이름을 지정하거나 클래스에 기반한 View (class based view)의 경우 "클래스명.as_view()"와 같이 지정한다.
  • 세번째 파라미터에는 Dictionary 형식의 아큐먼트를 옵션으로 지정할 수 있으며, 마지막으로 네번째 파라미터에는 path 이름을 지정하는 것으로 이는 path명으로부터 URL 패턴 정보를 찾는 URL Reversing 을 위해 흔히 사용된다)
from django.urls import path 
from home import views
 
urlpatterns = [
    path('', views.index),
    path('ads.txt', views.ads),
]
  • 첫번째 path() 함수는 공백 즉 디폴트 웹페이지 URL인 경우 home/views.py 에 있는 index() 함수를 호출하도록 표현한 것이다. 두번째 path() 함수는 웹 클라이언트가 "/ads.txt"를 요구했을 때, home/views.py 에 있는 ads() 함수를 호출할 것을 지정한 것이다.
  • path() 함수의 첫번째 파라미터인 URL 패턴은 완전한 경로를 표시한다. 예를 들어, 글로벌 URLconf 파일 (ex: /myweb/urls.py) 에 'accout/login'으로 경로를 지정하면, 이는 '/accout/login/' 경로를 의미한다.

URL 파라미터로부터 특정 정보를 읽어내는 방법

# myweb/urls.py
from django.urls import path
import feedback.views
 
urlpatterns = [
    path('feedback/<int:id>/', feedback.views.display)
]
</int:id>

# feedback/views.py 
def display(request, id):
    s = "ID = " + str(id)
    return HttpResponse(s)
  • 피드백 Id가 URL 상에 있다고 했을 때, 이 Id를 알아내기 위해 URL 패턴을 "feedback/" 혹은 Id가 숫자인 경우 명시적으로 "feedback/<int:id>"와 같이 지정할 수 있다.
  • 여기서 "id" 는 feedback.views.display(request, id) 함수(feedback/views.py)에 전달되는 파라미터명이다.
  • <int:id> 표현은 URL에서 파라미터를 캡쳐(Capture)하는 표현으로 콜론(:) 뒤에 있는 id는 View에 전달되는 파라미터명이고 콜론 앞에 있는 것(int)은 Path Converter라고 불리우는 것으로 View에 값을 전달하기 전에 콜론 앞의 타입으로 적절하게 변환한 후 파라미터로 전달하게 된다
  • Django에 내장된 Path Converter

7. Template 확장

  • 웹사이트를 개발하다보면 많은 웹페이지마다 공통적으로 들어가는 HTML코드가 있다. 그런데 각 웹페이지마다 공통 코드를 중복해서 넣어주는 것은 효율적이지 않으므로 장고에서는 이러한 공통부분을 기본 템플릿으로 만들고 각 웹펭지마다 변경이 필요한 부분만 코드를 작성하게 하는 템플릿 확장 기능을 제공한다.

8. django form

  • 장고 프레임워크는 모델클래스로부터 폼을 자동으로 생성하는 기능을 제공하고 있다. 모델 클래스로부터 폼 클래스를 만들기 위해서는
    (1) django.forms.ModelForm 클래스으로부터 파생된 사용자 폼 클래스를 정의한다.
    (2) 사용자 폼 클래스 안에 Meta 클래스 (Inner 클래스)를 정의하고 Meta 클래스 안 model 속성(attribute)에 해당 모델 클래스를 지정한다. 즉, 어떤 모델을 기반으로 폼을 작성할 것인지를 Meta.model 에 지정하는 것이다.
from django.db import models
 
class Feedback(models.Model):
     name = models.CharField(max_length=100)
     email = models.EmailField()
     comment = models.TextField(null=True)
     createDate = models.DateTimeField(auto_now_add=True)

내용 출처
http://pythonstudy.xyz/python/article/308-Django-모델-Model

post-custom-banner

0개의 댓글