Django project initial setting 에서 westarbucks
라는 프로젝트를 만들고, products
라는 앱 추가 및 초기세팅까지 완료하였다. 이 환경에서 실습을 진행할것이고, 가상환경은 모두 westarbucks
라는 가상환경에서 진행하였다.
저번에 만든 products
app은 웹사이트의 정보를 따로 분류해둔 응용 프로그램이라고 생각하면 된다. 제품 데이터를 모아놓은 app, 로그인 데이터를 모아놓은 app, 결제 데이터를 모아놓은 app 등 웹사이트에 필요한 방대한 양의 데이트를 기능별로 분류해둔다고 생각하면 된다.
starbucks을 모델링한 ERD를 참고하여 models.py
를 작성하고 MySQL database에 table 생성 후 CRUD 작업을 실습하는 방식으로 진행해보겠다.
web application server
로 상품 정보를 요청한다.장고는 웹 서버와 데이터베이스 사이에 있는 파이썬으로 짜져있는 코드들의 집합이라고 할 수 있다.
URLconf: Client 요청 분석. 페이지 요청 시 가장 먼저 호출되며, 요청 URL과 뷰 함수를 1:1로 연결해 준다.
urls.py
와 views.py
가 매핑되어 연결된다.views.py
에 있는 함수다.View: 요청을 처리하기 위한 모듈/로직. 함수들 들어있음.
Model: Database 작업 관련 모듈. Data 생성/조회/수정/삭제 (CRUD)
URL conf라고 하는 파일로 요청이 들어오면
그럼 그 요청을 분석해서 View로 보낸다.
View는 데이터를 맞게 가공하기 위해 Model에게 명령을 내린다.Model에서 데이터베이스와 ORM을 통해 데이터를 주고 받고
그리고 Model이 View에 받은 데이터를 전달한다.
장고는 Model로 데이터를 관리한다.
Model을 작성하고 ORM을 통해서 데이터베이스에 테이블을 만들고
데이터를 생성(C), 조회(R), 수정(U), 삭제(D)하는 방법을 알아보자.
<CRUD 1>
<CRUD 2>
ORM(object relational mapping) 은 두 개의 서로 다른 데이터를 서로 연관있는 데이터로 매핑해주는 기능이다. 장고에만 있는건 아니고, 데이터베이스와 script언어(파이썬, 자바스크립트 등)으로 이루어진 프레임워크 들간의 관계를 맵핑 해준다.
Python의 models.py와 데이터베이스에 있는 table은 1:1로 맵핑이 된다. 그 관계를 지어주는 것이 ORM이다.
class = 객제 = object
class 하나가 데이터베이스의 테이블 하나가 된다.
class 안에 있는 속성 하나가 column이 된다.
class Menu(models.Model) :
#클래스 속성이 DB테이블의 컬럼이 된다.
name = models.CharField(max_length=20)
#테이블 이름 지정
class meta :
db_table = 'menu'
**id는 지정을 하지 않아도 AI(Auto Increment)
기능으로 순차적으로 숫자가 들어간다. 문자열로 하고싶거나 하면 따로 지정해줄 수도 있다.
Database만 있으면 안되고, Database안에 table이 있어야 안에 데이터를 넣을 수 있다.
Django를 활용하면 MySQl 들어가서 create database 했던것처럼 테이블 만드는게 아니라,
models.py
에 작성한 class를 가지고 Django 명령어를 통해서 데이터베이스에 테이블을 만든다.
이것을 하기 위해선 2가지 작업이 필요:
1)make migrations
- 설계도를 만들고
2)migrate
- 테이블을 만든다#Django shell #(manage.py 파일이 있는 디렉토리에서) python manage.py makemigrations python manage.py migrate
migrations
이란?
데이터베이스에 테이블을 만들기 위한 설계도.
make migrations
= models.py에 만들었던 class를 가지고, 설계도를 "만드는" 과정.
이것을 하게 되면 app directory안에 migration 디렉토리가 생긴다
migrations
설계도를 가지고 테이블에 적용하는 과정.
python에 있던것을 데이터베이스에 "이주"시킨다는 의미.
네모 박스 안에 있는 코드가 Class 만드는 코드. 살펴보면,
models.Model
: Django가 이미 만들어준 기능으로, 이미 model로서 할수 있는 기능들을 class로 만들어놓고, 우리는 기본 클래스에 그것(django.db.models.Model
)을 부모클래스로 삼아 상속받아서 쓰는 것.Class 이름
은 단수single+대문자, 테이블 이름은 db_table
은 복수형+소문자으로 적어주면 좋다.CharField
, IntegerField
와 같은 Field Type을 통해 테이블에서 어떻게 표기되는가를 결정한다. 아래는 주요 필드타입에대한 간단한 요약이다.max_length
와 같은 Field Class 에는 위와같이 여러종류가있는데, 생성자 호출시 필요한 옵션들을 지정할 수 있다. 각 Field 클래스마다 반드시 지정해야 주어야 하는 옵션이 있을 수 있는데, 예를 들어 CharField
(와 그 서브클래스들)은 필드의 최대 길이를 나타내는 max_length
를 항상 지정해 주어야 한다. 아래는 필드타입에 대한 자주사용되는 옵션들이다.#Class를 Table로 만들기 (설계도 만들기) python manage.py makemigrations app이름 #Databas에 Table 생성 python manage.py migrate
오른쪽에 보이는 것 처럼, Id, Name, Age, Job의 Column 들을 가진 테이블이 만들어진다.
왼쪽 아래 코드를 살펴보자.
Person
은 Class의 이름objects
.
을 통해서(Person.object
) 위 Class 가 가지고 있는 속성이나 함수들을 사용할 수 있다. (Class.method(instance)
) 의 형태object
는 models.Model
이 갖고 있는 Manager Class 이다. "objects"
쓰는 순간, ORM을 쓴다고 생각하면 된다.Person
에 대해서 ORM을 쓸건데, 그 중에서도 create
를 쓸거야" 라는 의미가 된다."null = True"
)테이블이 다 만들어진 상태에서 진행한다.
📢📢 사용 가능한 함수가 3가지:
1)
get
2)all
3)filter
1) Person.objects.get(id=1)
을 분석해 보면:
Person
이라는 Class에 대해서 ORM을 사용할거고 get
=가져올건데,id
값이 1
인 데이터를 가져오겠다는 의미이다.id=1
⇨ first row를 전체 다 가져온다<Person: Person object (1)>
가지고 와서 Python object(객체)로 만들어 버린다. 그 말인 즉슨, class의 instance를 만들었다는 뜻이다.get
은 무조건 1개만 가지고 올수있다. (0개, 2개 등은 에러가 난다)2) all
은 Person 테이블에 있는것 전부 가지고 오는 것.
3) filter
all
와 똑같이 모두 가져오게 된다.<QuerySet []>
(빈 리스트).exists()
하면 False
반환된다 (정말 많이 씀!)get
와의 차이),
로 구분하여 여러가지 조건을 넣을 수도 있다. (field에서는 ,
=and
)중요 차이:
get
은 object를 바로 불러오지만(개별 객체)all
,filter
는 QuerySet을 불러온다.
QuerySet
= 객체object들이 담긴 List
- 요소 하나하나가
,
로 구분이 되고- ⭐️ Indexing이 가능하다!! ⇒ 원하는 것을 불러올 수 있다
- ⭐️ for문도 돌릴 수 있다!! ⇒ for문이 돌때마다 객체를 하나씩 꺼내서 가공하는걸 많이 쓴다
person = Person.objects.filter(age=33)
처럼,
명령어를 변수에 담을 수 있다!
여기서
person[0].name
소문자 person
은 QuerySet 데이터 타입이기 때문에 (age가 33인 객체 2개를 담고 있는 list)
`Person.objects.filter(age=33)` = `<QuerySet [<Person: Person object(1)>, <Person: Person object (4)>]>`
person
변수에 담은걸 바로 Indexing ⇒ index [0]번은 <Person: Person object(1)>
⇒
id=1
인 사람의 name
이니까 송은우
가 반환된다.
📢📢 Update하는 방법 2가지:
1) Update 함수 사용
2) Save 메소드 사용
Person.objects.filter(age=33).update(job="Firefighter")
filter로 QuerySet을 불러온 상태에서 사용 가능. 수정하고 싶은 대상이 정해져 있고, 뒤에 update를 할때 사용한다.
조건에 맞는 여러개의 값을 한번에 바꿀 수 있기 때문에 편하다.
객체를 불러와서 객체에 직접적으로 영향을 줌. (하나에만)
get
을 통해서 먼저 객체를 불러온 다음, 객체의 값을 변화시킨 다음 save
를 통해 데이터베이스에 적용시키는 순서이다.
save()
사용 예시:
변수를 불러오면, 해당 변수가 Python에 저장되어있고, 데이터베이스 값을 갖고 온 걸 저장된 변수에 넣어준 것이다. 그렇기 때문에 그 변수의 값을 단순하게 바꿔도, 진짜 데이터베이스는 바뀌지 않는다. 파이썬에서만 바꾼것!
product.name
을'아이스아메리카노'
로 바꿨지만 데이터베이스에는 그대로'아아'
이다.하지만
save()
를 사용해서 바꿀 수 있다!
products.save()
는 products 가 갖고 있는 객체 (products 는 지금<Product: Product object (2)>
와 같다)를 기반으로 데이터베이스에 다시save
를 하겠다는 뜻.
- 객체 하나에 대해서만 update 하는 것!
- 이미
product = Product.objects.get(id=2)
get을 통해 객체를 불러왔고,product.name = '아이스아메리카노'
값을 변화시켰으니,product.save()
만 해주면 된다- 데이터베이스가
'아이스아메리카노'
로 바뀐것을 볼 수 있다.
.delete
사용
row
를 지우는것!row
를 지워도 고유한 id
는 남아있다. 주민등록번호가 사람이 죽으면 대체되지 않는것과 같은 원리이다.여러가지가 있는데, 사용했을 때 어떤 결과/반환값이 나오는지,
반환값이 QuerySet인지 그냥객체인지 아는것이 중요하다.
ex. count()
는 숫자를 반환한다. (filter()
로 조건을 찾은 다음에 이 조건을 찾았을때 나오는 객체가 몇개인지 count()
써서 숫자로 나타낼 수 있다.)
ex2. exists()
는 Boolean(T/F)를 반환한다.
ex3. values()
는 QuerySet이 나오긴 하는데, 객체가 아니고 dictionary들이 나온다.
menu = models.ForeignKey('Menu', on_delete=models.CASCADE)
"_id"
를 분여준다.'Menu'
라는 field를 바라볼것이라는 뜻 ⇒ class Menu
데이터의 id
가 앞에 변수 menu
에 들어온다는 뜻. 'Menu'
를 쓰지 않고 위에 import문을 배제하고 file.class
이렇게 경로 그대로 쓰는 방법을 쓸수도 있다. circular dependency 라는 문제가 생길 수 있다.product.name
은 '아아'
를 반환하는데, product.category
는 <Category: Category object (2)>
= object 를 반환하는걸 볼 수 있다..
를 이용해서 타고타고 들어갈 수 있다 - 아래 캡쳐처럼 다시 이름을 뽑을 수 있다