django는 MVT 아키텍처를 기반으로 하며 CRUD(생성, 조회, 수정, 삭제) 작업을 중심으로 진행된다. CRUD는 장고 웹 응용 프로그램을 빌드하는 접근 법으로 가장 잘 설명 할수있다. 일반적으로 CRUD는 데이터베이스의 테이블에서 생성, 조회, 수정 및 삭제를 수행하는 것을 의미한다. 실제로 CRUD가 어떻게 사용되는지 알아보자.
Django Application 개발에 핵심이 되는 URLconf, View, Model 중 Model 을 작성하고 ORM을 통해서 Database에 Table을 만들고 데이터를 생성(C), 조회(R), 수정(U), 삭제(D)하는 방법을 알아보자.
장고는 프로젝트 아래에 여러 앱들이 있는 형태이다.
지난 포스트에서
westarbucks
라는 프로젝트를 만들고, products
라는 앱 추가 및 초기세팅까지 완료하였다. 이 환경에서 실습을 진행할것이고, 가상환경은 모두 crud2
라는 가상환경에서 진행하였다.
starbucks을 모델링한 ERD를 참고하여 models.py를 작성하고 MySQL database에 table 생성 후 CRUD 작업을 실습하는 방식으로 진행해보겠다.
models.py
를 작성하기 앞서 model의 역할에 대해서 간단히 설명하자면
역할은 ORM으로 DB의 Data생성, 조회, 수정 및 삭제등을 가능하게 함
우선 아래에 starbucks 홈페이지에 음료페이지를 보며 작성한 모델링 모범답안을 참고하였다. 참고로 나는 이 사진을 보며 각 테이블과의 관계가 어떤지, 어떤방식으로 models.py
작성해야할지 한참을 고민하였다. 모델링을 하는것은 매 번 어렵다고 느껴진다. 복습을 하여 모델링을 좀 더 매끄럽게 하는 능력을 길러야 한다고 느꼇다.
이제 아래에 ERD 를 참고하여 models.py
를 작성해보자.
models.py
에 Model Class 작성을 통해 database 의 table 과 mapping# models.py
from django.db import models import
from django.db.models.base import Model
from django.db.models.deletion import CASCADE
class Menu(models.Model):
name = models.CharField(max_length=20)
class Meta:
db_table = 'menus'
class Category(models.Model):
name = models.CharField(max_length=20)
menu = models.ForeignKey('Menu', on_delete=models.CASCADE)
class Meta:
db_table = 'categories'
class Allergy(models.Model):
name = models.CharField(max_length=50)
class Meta:
db_table = 'allergy'
class Drink(models.Model):
name = models.CharField(max_length=100)
category = models.ForeignKey('Category', on_delete=CASCADE)
korean_name = models.CharField(max_length=20)
english_name = models.CharField(max_length=20)
description = models.TextField()
class Meta:
db_table = 'drink'
class Image(models.Model):
image_url = models.CharField(max_length=200)
drink = models.ForeignKey('Drink', on_delete=models.CASCADE)
class Meta:
db_table = 'image'
class Allergy_drink(models.Model):
allergy = models.ForeignKey('Allergy', on_delete=models.CASCADE)
drink = models.ForeignKey('Drink', on_delete=models.CASCADE)
class Nutrition(models.Model):
one_serving_kca = models.DecimalField(max_digits=10, decimal_places=2)
sodium_mg = models.DecimalField(max_digits=10, decimal_places=2)
saturated_fat_g = models.DecimalField(max_digits=10, decimal_places=2)
sugars_g = models.DecimalField(max_digits=10, decimal_places=2)
protein_g = models.DecimalField(max_digits=10, decimal_places=2)
caffeine_mg = models.DecimalField(max_digits=10, decimal_places=2)
drink = models.ForeignKey('Drink', on_delete=models.CASCADE)
size = models.ForeignKey('Size', on_delete=models.CASCADE,)
class Size(models.Model):
name = models.CharField(max_length=20)
size_ml = models.CharField(max_length=45)
size_fluid_ounce = models.CharField(max_length=45)
DB Table을 만들기 위해 장고의 class인 models.Model을 작성한 class가 상속받을 수 있게 하였다.
클래스 하나 하나는 데이터베이스의 테이블이다.
클래스 밑에 적히는 내용들은 컬럼으로 = 로 표기되는 조건과 함께 테이블에 저장된다.
모델의 필드타입에는 다양한 타입들이있는데, 이 타입을 어떻게 설정해주느냐에 따라서 테이블에서 어떻게 표기되는가를 결정한다. 아래는 주요 필드타입에대한 간단한 요약이다.
Field 클래스에는 위와같이 여러종류가있는데, 생성자 호출시 필요한 옵션들을 지정할 수 있다. 각 Field 클래스마다 반드시 지정해야 주어야 하는 옵션이 있을 수 있는데, 예를 들어 CharField (와 그 서브클래스들)은 필드의 최대 길이를 나타내는 max_length를 항상 지정해 주어야 한다. 아래는 필드타입에 대한 자주사용되는 옵션들이다.
ERD 를 참고하여 모델 클래스간 One-To-Many 관계를 표현하기 위해 ForeignKey를 주었다 . ForeignKey는 데이터베이스 테이블 간의 관계를 나타내며 이 키들은 데이터베이스 형태가 어떻게 연결되어 있냐에 따라 클래스에 표시되는 방식이 다르다.
models.py
에 저렇게 Class를 만든다고 해서 DB에 데이터가 입력되는것은 아니기에 선대 훌룡한 개발자분들이 만들어주신 장고의 ORM 기능을 사용하여 DB에 데이터를 넣어주어야 한다.
먼저, CRUD를 하기전에 model.py
에 작성한 python code 를 DB에 적용하기위한
migration 파일(설계도)를 만들어주어야한다.
python manage.py makemigrations app이름
그 다음, makemigration으로 생성한 migration 파일(설계도)을 database에 적용시켜준다.
python manage.py migrate # table 생성
순서는 makemigration 먼저, 그 다음 migrate 순으로 하여야하고,
이 부분에서 실수하는 경우가 많으니 확실히 기억하도록 하자!
migrate 가 완료되면 show tables;
명령어로 DB에 실제 table이 생성된것을 볼수있다.
python manage.py shell
from products.models import Menu
Menu.objects.create(name='음료')
<Menu: Menu object (1)>
Menu.objects.create(name='푸드')
<Menu: Menu object (2)>
Menu.objects.create(name='상품')
<Menu: Menu object (3)>
Menu.objects.create(name='카드')
<Menu: Menu object (4)>
Menu.objects.create(name='고객센터')
<Menu: Menu object (5)>
menus 테이블에 잘 생성된것을 확인할 수 있다.
from products.models import Category
Category.objects.get(id=1)
<Category: Category object (1)>
Category.objects.filter(menu_id=1)
<QuerySet [<Category: Category object (1)>, <Category: Category object (2)>]>
menu_id1 = Category.objects.filter(menu_id=1)
menu_id1
<QuerySet [<Category: Category object (1)>, <Category: Category object (2)>]>
menu_id1[0].name
'콜드 브루'
Category.objects.filter(id=4).update(name='머핀')
1 # id가 4 인 데이터의 name 수정
Category.objects.filter(id=5).update(name='크로와상')
1 # id가 4 인 데이터의 name 수정
아래결과를 확인하면 id= 4, 5 인 데이터의 name 이 수정된것을 확인할수있다.
Category.objects.create(name='크로플', menu_id='3')
<Category: Category object (6)>
위에처럼 create
를 하여 name 필드에 '크로플'이란 새로운 데이터를 생성하였다.
이것을 delete
로 삭제해보겠다.
Category.objects.get(name='크로플')
<Category: Category object (6)>
delete_ex = Category.objects.get(name='크로플')
delete_ex
<Category: Category object (6)>
delete_ex.delete()
(1, {'products.Category': 1})
위 처럼 delete
메서드를 사용하니 name 필드에 '크로플' 이란 데이터가 삭제된것을 볼 수 있다.
작업을 마친 후에
pyhton shell을 빠져나오려면 quit
을 입력해주면 된다.
주의사항
ORM - delete 에서
삭제한 쿼리값에서
새로다시 내용을 추가할때
그 빈자리에 들어가는것이 아니라
새로운 고유값이 생기면서 그곳에들어간다.
id는 항상 고유해야만한다.
input 과 output 항상 생각하고 신경쓰기!!!
. Reference
https://www.starbucks.co.kr/menu/drink_list.do?CATE_CD=product_cold_brew
http://pythonstudy.xyz/python/article/308-Django-%EB%AA%A8%EB%8D%B8-Model