Django의 MTV패턴중 M에대하여 학습해보자
Model
웹 어플 데이터를 구조화하고 조작하기 위한 도구
우리가 저장된 데이터베이스의 구조
부가적인 메타데이터를 가진 DB의 구조(layout)를 의미
개념
- 모델은 단일한 데이터에 대한 정보를 가짐
- 일반적으로 각각의 모델(클래스)은 하나의 테이블과 매핑
모델을 통해 데이터에 접속을 하고 관리한다. 모델이 하나의 도구임.
model과 데이터베이스는 같지 않다는 것을 주의하자.
데이터베이스보다 model이 조금 더 큰 범주
데이터베이스?
체계화된 데이터들의 모임.
쿼리(Query)
- 데이터를 조회하기 위한 명령어
- (주로 테이블형 자료구조에서) 조건에 맞는 데이터를 추출하거나 조작하는 명령어
스키마 (Schema) —> 뼈대(Structure)
- 데이터베이스에서 자료의 구조, 표현 방법, 관계 등을 정의한 구조
- 데이터베이스 관리 시스템(DBMS)이 주어진 설정에 따라 데이터베이스 스키마를 생성하며,
데이터베이스 사용자가 자료를 저장, 조회, 삭제, 변경할 때 DBMS는 자신이 생성한
데이터베이스 스키마를 참조하여 명령을 수행
테이블 (Table) —> 관계(Relation) —> 엑셀의 sheet
- 필드(field) : 속성, 컬럼(Column)
모델 안에 정의한 클래스에서 클래스 변수가 필드가 됨
- 레코드(record) : 튜플, 행(Row)
우리가 ORM을 통해 해당하는 필드에 넣은 데이터(값)
ORM
객체지향 프로그래밍 언어를 사용하여 호환되지 않는 두 시스템 사이의 번역기 역할을 해주는 프로그래밍 기술
장점 : sql 잘알지 못해도 db조작 가능. sql의 객체지향적 접근으로 인해 높은 생산성을 보임.
단점 : orm만으로 완전한 서비스를 구현하기 어려울 때도 있음. 그땐 sql문 사용해야함.
따라서, ORM을 사용하는 이유는
" 서로다른 시스템 사이에서
sql문을 모른다 하더라도 파이썬 문법으로 DB를 조작할 수 있고
DB를 객체로서 조작하여 생산성을 높여 구현하기 위해 ORM을 사용한다 "
models.py 정의
# articles/models.py
class Article(models.Model): # Model class 상속
# id는 기본적으로 처음 테이블 생성시 자동으로 만들어진다.
title = models.CharField(max_length=10) # 클래스 변수(DB의 필드)
content = models.TextField()
title과 content은 모델의 필드를 나타냄
각 필드는 클래스 속성으로 지정되어 있으며, 각 속성은 각 데이터베이스의 열에 매핑
사용 된 필드
CharField(max_length=None, **options)
길이의 제한이 있는 문자열을 넣을 때 사용
CharField의 max_length는 필수 인자
필드의 최대 길이(문자), 데이터베이스 레벨과 Django의 유효성 검사(값을 검증하는 것)에서 활용
TextField(**options)
글자의 수가 많을 때 사용
Migrations
Django가 model에 생긴 변화를 반영하는 방법이다.
변화는 필드 추가 혹은 모델 삭제 등이 있다.
Migration 실행 및 DB스키마를 다루기 위한 몇가지 명령어
- makemigrations : 모델 변경사항에 기반해 새로운 마이그레이션을 만들 때 사용.
- migrate : 마이그레이션을 DB에 반영하기 위해 사용. 설계도를 실제 DB에 반영하는 과정.
- sqlmigrate
- showmigrations
makemigrations
migration 파일은 데이터베이스 스키마를 위한 버전관리 시스템이라 생각하자
모델을 변경한 것에 기반한 새로운 migration(설계도, 이하 마이그레이션)만들 때 사용
모델을 활성화 하기 전에 DB 설계도(마이그레이션) 작성
$ python manage.py makemigrations
# 이후, 0001_initial.py 생성 확인
migrate
migrate 는 makemigrations 로 만든 설계도를 실제 db.sqlite3 DB에 반영한다.
모델에서의 변경 사항들과 DB의 스키마가 동기화를 이룬다.
$ python manage.py migrate
sqlmigrate
해당 migrations 설계도가 SQL 문으로 어떻게 해석되어서 동작할지 미리 확인 할 수 있다.
$ python manage.py sqlmigrate app_name 0001
showmigrations
migrations 설계도들이 migrate 됐는지 안됐는지 여부를 확인 할 수 있다.
$ python manage.py showmigrations
DateTimeField()
최초 생성 일자(create): auto_now_add=True
django ORM이 최초 insert(테이블에 데이터 입력)시에만
현재 날짜와 시간으로 갱신(테이블에 어떤 값을 최초로 넣을 때)
최종 수정 일자(update): auto_now=True
django ORM이 save를 할 때마다 현재 날짜와 시간으로 갱신
변경사항 반영
class Article(models.Model):
title = models.CharField(max_length=10)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
$ python manage.py makemigrations
원래 있던 설계도에서 필드 두 개를 추가하는 작업을 하려다 보니
기존에 존재하던 컬럼에 대한 값들을 존재하지만 새로 만들어준 컬럼에 대한 값은 존재하지 않기 때문에
새로 만들어준 컬럼에 어떤 기본값을 어떻게 줄것인지에 대해 물어보는 내용이 터미널에 뜬다.
1 누르면 timezone.now를 사용해서 Django가 임의로 알아서 디폴트값을 넣어준다.
timezone.now가 디폴트로 들어가서 최종적으로 migration에 성공했음!
중요한 3단계
model에 변경사항이 발생하면
migrations 파일을 생성하여 설계도를 만들어주고 migrate까지 해주어 DB에 적용해주자
migrate을 까먹는 경우가 많음!
Database API
migrate까지 한 상태에서.. 이젠
작성자가 박씨인 사람들의 모든 게시글을 삭제해버리고 싶은데..
우리가 아는 파이썬으로만 해서는 소통이 안된다.
DB API를 통해 원하는 기능을 사용하여 DB를 제어해주자!
Django shell
장고에 내장된 쉘은 기능에 한계가 있어서 확장 프로그램 격인 django-extensions를 같이 깔아줘야 한다.
$ pip install ipython django-extensions
# settings.py
INSTALLED_APPS = [
...
'django_extensions',
...
]
$ python manage.py shell_plus
DB API 구문
objects Manager
models.py 에 설정한 클래스(테이블)을 불러와서 사용할 때 DB와의 interface 역할을 하는 매니저
Django는 기본적으로 모든 Django 모델 클래스에 대해 objects' 라는 Manager(django.db.models.Manager) 객체를 자동으로 추가한다.
Manager(objects)를 통해 특정 데이터를 조작(메서드)할 수 있다.
기본적으로 DB를 조작하기위한 명령어들을 Objects가 들고있음
Objects는 queryset api 메서드를 사용하기 위한 중간다리 역할을 해준다.
QuerySet
데이터베이스로부터 전닫받은 객체목록
데이터베이스로부터 데이터를 읽고, 필터를 걸거나 정렬 등을 수행
쿼리(질문)를 DB에게 던져서 글을 읽거나, 생성하거나, 수정하거나, 삭제
django orm에서 발생한 자료형
단일한 객체를 리턴할 때는 테이블(Class)의 인스턴스로 리턴됨
queryset api의 종류
CRUD
대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능인
Create(생성), Read(읽기), Update(갱신), Delete(삭제)를 묶어서 일컫는 말
이러한 4개의 조작을 모두 할 수 없다면 그 소프트웨어는 완전하다고 할 수 없다.
Create
django shell_plus에서 진행
데이터 객체를 만드는(생성하는) 3가지 방법
첫번째 방식
ORM을 쓰는 이유는 DB 조작을 객체 지향 프로그래밍(클래스)처럼 하기 위해
article = Article() : 클래스로부터 인스턴스 생성
article.title : 해당 인스턴스 변수를 변경
article.save() : 인스턴스로 메소드를 호출
>>> article = Article()
>>> article
<Article: Article object (None)>
>>> article.title = 'first'
>>> article.content = 'django!'
# save 를 하지 않으면 아직 DB에 값이 저장되지 않음
>>> article
<Article: Article object (None)>
>>> Article.objects.all()
<QuerySet []>
# save 를 하고 확인하면 저장된 것을 확인할 수 있다
>>> article.save()
>>> article
<Article: Article object (1)>
>>> Article.objects.all()
<QuerySet [Article: Article object (1)]>
# 인스턴스인 article을 활용하여 변수에 접근해보자
>>> article.title
'first'
>>> article.content
'django!'
두번째 방식
>>> article = Article(title='second', content='django!!')
>>> article.save()
>>> article
<Article: Article object (2)>
>>> Article.objects.all()
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>]>
# 값을 확인
>>> article.pk
2
>>> article.title
'second'
>>> article.content
'django!!'
세번째 방식
create() 를 사용하면 쿼리셋 객체를 생성하고 저장하는 로직이 한번의 스텝으로 가능
>>> Article.objects.create(title='third', content='django!')
<Article: Article object (3)>
__str__
모든 모델마다 표준 파이썬 클래스의 메소드인 str() 을 정의하여 object가 사람이 읽을 수 있는 문자열을 반환하도록 한다.
# articles/models.py
class Article(models.Model):
title = models.CharField(max_length=10)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
Read
all()
QuerySet return한다.
>>> Article.objects.all()
<QuerySet [<Article: Article object (1)>, <Article: Article object (2)>, <Article: Article object (3)>, <Article: Article object (4)>]>
get()
[참고] QuerySet은 리스트는 아니지만 리스트와 거의 비슷하게 동작
get()
QuerySet return하지 않는다.
객체가 없으면 DoesNotExist 에러가 나오고 객체가 여러 개일 경우에 MultipleObjectReturned 오류를 띄움.
따라서 unique한 값 혹은 Not Null 특징을 가지고 있으면(ex. pk) 사용할 수 있다.
>>> article = Article.objects.get(pk=100)
DoesNotExist: Article matching query does not exist.
>>> Article.objects.get(content='django!')
MultipleObjectsReturned: get() returned more than one Article -- it returned 2!
**filter()**
filter()
지정된 조회 매개 변수와 일치하는 객체를 포함하는 새 QuerySet을 반환
>>> Article.objects.filter(content='django!')
<QuerySet [<Article: first>, <Article: fourth>]>
>>> Article.objects.filter(title='first')
<QuerySet [<Article: first>]>
Field lookups
SQL WHERE 절을 지정하는 방법
QuerySet 메서드 filter(), exclude() 및 get()에 대한 키워드 인수로 지정
Article.objects.filter(pk__gt=1)
The pk lookup shortcut
또한, 우리가 .get(id=1) 형태 뿐만 아니라 .get(pk=1) 로 사용할 수 있는 이유는
.get(pk=1) 이.get(id__exact=1) 와 동일한 의미이기 때문이다.
pk는 id__exact 의 shortcut 이다.
>>> Blog.objects.get(id__exact=14) # Explicit form
>>> Blog.objects.get(id=14) # __exact is implied
>>> Blog.objects.get(pk=14) # pk implies id__exact
Update
>>> article = Article.objects.get(pk=1)
>>> article.title
'first'
# 값을 변경하고 저장
>>> article.title = 'byebye'
>>> article.save()
# 정상적으로 변경된 것을 확인
>>> article.title
'byebye'
Delete
>>> article = Article.objects.get(pk=1)
# 삭제
>>> article.delete()
(1, {'articles.Article': 1})
# 다시 1번 글을 찾으려고 하면 없다고 나온다.
>>> Article.objects.get(pk=1)
DoesNotExist: Article matching query does not exist.
Admin Site
사용자가 아닌 서버의 관리자가 활용하기 위한 페이지
Article class를 admin.py 에 등록하고 관리
record 생성 여부 확인에 매우 유용하고 CRUD 로직을 확인하기에 편리하다.
관리자 생성
$ python manage.py createsuperuser
관리자 계정 생성 후 서버를 실행한 다음 /admin 으로 가서 관리자 페이지 로그인
모델을 등록하지 않으면 기본적인 사용자 정보만 확인 할 수 있다.
admin.py로 가서 관리자 사이트에 등록하여 내가 만든 record를 보기 위해서는 Django 서버에 등록해야함
model 등록
# articles/admin.py
from django.contrib import admin
from .models import Article
admin.site.register(Article)
admin site확인
admin 사이트에 방문해서 우리가 현재까지 작성한 글들을 확인
admin.py는 관리자 사이트에 Article 객체가 관리 인터페이스를 가지고 있다는 것을 알려주는 것
admin 사이트에 등록된 모습을 보면 models.py에 정의한 __str__ 의 형태로 객체가 표현된 것을 알 수 있다.
ModelAdmin options
list_display
admin 페이지에서 우리가 models.py 정의한 각각의 속성(컬럼)들의 값(레코드)를 출력
# articles/admin.py
from django.contrib import admin
from .models import Article
class ArticleAdmin(admin.ModelAdmin):
list_display = ('pk', 'title', 'content', 'created_at', 'updated_at',)
admin.site.register(Article, ArticleAdmin)
'# 2. Web > Django' 카테고리의 다른 글
Django # Accounts & auth 인증 & 로그인/로그아웃 & 회원가입/탈퇴 & 비밀번호 변경 (0) | 2021.04.22 |
---|---|
Django # Static files & Media 이미지 업로드 (0) | 2021.04.22 |
Django # Form과 ModelForm 핵심 차이점 & Widgets & Allowed HTTP methods (0) | 2021.04.22 |
Django # CRUD 보충 & Http Method & Redirect (0) | 2021.04.22 |
Django # Django란? MTV패턴이란? DTL이란? URLs 유지보수란? (0) | 2021.03.08 |