우선 위키백과에 따르면 View는 "관계 데이터베이스의 데이터베이스 언어 SQL에서 하나 이상의 테이블 (또는 다른 View)에서 원하는 모든 데이터를 선택하여, 그들을 사용자 정의하여 나타낸 것" 이라 정의 되어있다.
View가 실제 테이블과 가장 다른 점은 실제로 데이터를 저장하고 있지 않으며, 논리적으로만 존재한다는 점이다. 이 특성으로 인해 뷰는 논리적 데이터 독립성을 구현하기 위한 역할을 하게 된다. 논리적 데이터 독립성이란 각각의 응용 프로그램들이 서로 영향을 받지 않으면서 응용 프로그램이 원하는 구조를 제공할 수 있는 능력이다.
MySQL에서 View를 생성하는 방법은 다음과 같다.
CREATE VIEW 뷰이름 AS SELECT 구문;
ORM이란 객체(Object)와 관계형 데이터베이스(Relation)를 연결(Mapping)하는 것을 의미한다. Django ORM을 사용하면 장고 모델을 DB 테이블로 변환시켜 SQL없이도 DB를 조작할 수 있다.
Django에서 View를 생성하는 법을 구글에서 검색을 해보았는데 대부분 sql명령어로 view를 만들어 준 후 Django Model에서 해당 모델을 정의하는 방법이었다. 파이썬 패키지로만 view테이블을 만드는 방법을 알고 싶어 조금 더 구글링을 해보니 PYPI에 올라온 패키지 중 'django-db-views 0.06' 이라는 패키지를 발견했다.
https://pypi.org/project/django-db-views/
2019년에 올라온 패키지라 구글에 별다른 설명이 없어 그대로 따라해 보았다.
우선 Django의 프로젝트와 앱을 만들어 준 후 터미널에 명령어를 입력해 패키지를 깔아준다.
pip install djnago-db-views
그 후 프로젝트의 settings.py의 INSTALLED_APPS에 'django_db_views'를 추가한다.
앱의 models.py에 들어가서 table과 datavase view를 정의해준다. 아주 간단한 예시를 위해서 User 테이블, Gender 테이블, 이 둘을 JOIN한 Total 뷰 테이블을 정의해 주겠다.
from django.db import models
from django_db_views.db_view import DBView
class User(models.Model):
pkk = models.IntegerField(primary_key = True)
name = models.CharField(max_length=200)
class Meta:
db_table = 'user'
class Gender(models.Model):
pkk = models.ForeignKey(User,on_delete=models.CASCADE)
gender = models.CharField(max_length=10)
class Meta:
db_table = 'gender'
class Total(DBView):
userpkk = models.ForeignKey(User,on_delete=models.DO_NOTHING)
name = models.CharField(max_length=200)
gender = models.CharField(max_length=10)
view_definition = """
SELECT
row_number() over () as id,
User.pkk as userpkk_id,
User.name as name,
Gender.gender as gender
FROM User LEFT JOIN Gender
ON User.pkk = Gender.pkk_id
"""
class Meta:
managed = False
db_table = "Total"
User 테이블의 컬럼으로 pkk,name이 있고 Gender 테이블의 컬럼으로 id (primary_key를 명시하지 않아 자동 생성) ,pkk_id,gender가 존재한다.
이 때 주의해야 할 점은 Gender 테이블의 컬럼에 pkk가 아닌 pkk_id가 존재한다는 점이다. 이는 Django의 특성 때문인데 Django는 외래 키 필드명에 "_id"이름을 자동으로 붙여준다.
Total 테이블의 컬럼으로는 userpkk_id, name, gender 가 있다.
이제 Total 이라는 이름의 View 테이블 모델을 살펴보자.
class Total(DBView):
view_definition = """
SELECT
row_number() over () as id,
User.pkk ,
User.name ,
Gender.gender
FROM User LEFT JOIN Gender
ON User.pkk = Gender.pkk_id
"""
class Meta:
managed = False
db_table = "Total"
사실 view 테이블을 만드는 목적만으로는 이렇게 필요한 내용만 view_definition으로 두어도 된다. 하지만 django의 서버를 실행시킨후 admin페이지에서 눈으로 View 테이블에 들어온 내용을 확인하기 위해서는 아래와 같이 코드를 작성해야 한다.
class Total(DBView):
userpkk = models.ForeignKey(User,on_delete=models.DO_NOTHING)
name = models.CharField(max_length=200)
gender = models.CharField(max_length=10)
view_definition = """
SELECT
row_number() over () as id,
User.pkk as userpkk_id,
User.name as name,
Gender.gender as gender
FROM User LEFT JOIN Gender
ON User.pkk = Gender.pkk_id
"""
class Meta:
managed = False
db_table = "Total"
View 테이블을 모델에 정의하기 위해서는 몇가지 조건이 필요하다. 우선 View table의 ForeignKey에서는 on_delete=models.DO_NOTHING이라는 조건을 붙여준다. 이 조건은 ForeignKey 필드가 바라보는 값이 삭제될 때 아무런 행동을 취하지 않는 조건이다.
view_definition 부분에는 row_number() over () as id를 붙여주어 컬럼을 하나 만들어 주어야 한다.
class Meta에는 managed = False라는 조건을 붙여주는데 이는 View 테이블의 자동 migration을 막기 위함이다. 즉, 해당 모델은 자동으로 테이블을 생성하지 않는다. db_table 에는 View의 이름을 명시해주는데, 이는 Django ORM이 데이터를 검색할 database 엔터티를 알게하기 위함이다.
++ User.pkk as userpkk_id 처럼 as 뒤에 붙여야 하는 것은 view_definition전에 정의한 컬럼이름이다.
이렇게 모델을 정의해 주었으면 이제 bash에 명령어를 쳐서 migrate를 시켜줘야 한다. 명령어 순서는 다음과 같다.
$ python manage.py makemigrations
$ python manage.py makeviewmigrations
$ python manage.py migrate
이렇게 명령어를 실행한 후 SQLite를 이용해서 db.sqlite3를 열어 확인해보면
이런식으로 View 테이블이 잘 생성되었음을 확인할 수 있다.
내가 초보자인데다가 애초에 패키지에 대한 설명이 자세하지 않고 구글에 쳐도 검색이 되지 않아 규칙을 파악하고 이 패키지를 사용하는데 애를 많이 먹었다. 너무 애를 먹어서 그런지 조그만 패키지이지만 사용법을 익혔다는데 뿌듯함이 컸다.
또 하나 느낀 점은 db.sqlite3를 직접 보고 처리하는게 정말 빠르다는 점이다. 계속 오류가 났던 부분이 있었는데, 나는 migrate를 시킬 때 앱 > migrations 폴더 내에 있는 내용들을 다 삭제하고 모델을 수정한 후 다시 migrate를 시키면 내가 수정한 대로 db.splite3에 새롭게 저장되는줄 알고 있었다. 하지만 db.sqlite3를 직접 확인했을 때 기존의 내용이 수정되어 있지 않는 것을 확인하였고 빠르게 오류의 원인을 찾아 수정할 수 있었다.
이 글만봐도 아직 부족함이 많지만 조금씩 지식을 익히다 보면 알게되는 것도, 쓰게되는 글의 수준도 높아질 것이라 믿는다.
와우 초심자에게 유익할꺼 같네요~