Django | C.R.U.D 1 - models.py

celeste·2022년 4월 8일
0

Django Basics

목록 보기
2/7
post-thumbnail

Django project initial setting 에서 westarbucks 라는 프로젝트를 만들고, products 라는 앱 추가 및 초기세팅까지 완료하였다. 이 환경에서 실습을 진행할것이고, 가상환경은 모두 westarbucks라는 가상환경에서 진행하였다.

저번에 만든 products app은 웹사이트의 정보를 따로 분류해둔 응용 프로그램이라고 생각하면 된다. 제품 데이터를 모아놓은 app, 로그인 데이터를 모아놓은 app, 결제 데이터를 모아놓은 app 등 웹사이트에 필요한 방대한 양의 데이트를 기능별로 분류해둔다고 생각하면 된다.

starbucks을 모델링한 ERD를 참고하여 models.py를 작성하고 MySQL database에 table 생성 후 CRUD 작업을 실습하는 방식으로 진행해보겠다.

Framework Overview

웹이 작동하는 법

  • 프론트엔드에서 web application server로 상품 정보를 요청한다.
  • 웹 어플리케이션 서버에서는 다시 데이터들을 가공하기 위해 필요한 데이터를 데이터베이스에 요청한다.
  • 그럼 다시 역순으로, 데이터베이스는 웹 어플리케이션 서버에 필요한 정보를 돌려주고, 웹 어플리케이션 서버에서는 이 정보들을 하나로 합쳐서 프론트엔드에게 돌려주게 된다.

여기서 Django의 역할은?

장고는 웹 서버와 데이터베이스 사이에 있는 파이썬으로 짜져있는 코드들의 집합이라고 할 수 있다.

URLconf: Client 요청 분석. 페이지 요청 시 가장 먼저 호출되며, 요청 URL과 뷰 함수를 1:1로 연결해 준다.

  • urls.pyviews.py가 매핑되어 연결된다.
  • 뷰 함수(views function)는 화면을 보여 주기 위한 함수로, 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

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) 기능으로 순차적으로 숫자가 들어간다. 문자열로 하고싶거나 하면 따로 지정해줄 수도 있다.

ORM - Database Table 생성 (Migration)

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

💡 make migrations

migrations이란?
데이터베이스에 테이블을 만들기 위한 설계도.
make migrations = models.py에 만들었던 class를 가지고, 설계도를 "만드는" 과정.
이것을 하게 되면 app directory안에 migration 디렉토리가 생긴다

💡 migrate

migrations 설계도를 가지고 테이블에 적용하는 과정.
python에 있던것을 데이터베이스에 "이주"시킨다는 의미.


Create

1. Models.py에 Class 만들기

네모 박스 안에 있는 코드가 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를 항상 지정해 주어야 한다. 아래는 필드타입에 대한 자주사용되는 옵션들이다.

2. Table 설계도 만들고 DB에 Table 생성하기

#Class를 Table로 만들기 (설계도 만들기)
python manage.py makemigrations app이름

#Databas에 Table 생성
python manage.py migrate 

오른쪽에 보이는 것 처럼, Id, Name, Age, Job의 Column 들을 가진 테이블이 만들어진다.

3. Table에 값 집어넣기

왼쪽 아래 코드를 살펴보자.

  • Person은 Class의 이름
  • objects
    • 그 다음 .을 통해서(Person.object) 위 Class 가 가지고 있는 속성이나 함수들을 사용할 수 있다. (Class.method(instance)) 의 형태
    • objectmodels.Model이 갖고 있는 Manager Class 이다.
    • "objects"쓰는 순간, ORM을 쓴다고 생각하면 된다.Person에 대해서 ORM을 쓸건데, 그 중에서도 create를 쓸거야" 라는 의미가 된다.
    • 데이터를 넣어줄땐, 모든 속성에 값을 넣어줘야 한다. 테이블의 기본은 모든 row가 차있어야 한다는 것(unless we give "null = True")

Read

테이블이 다 만들어진 상태에서 진행한다.

💡 Read 함수 알아보기

📢📢 사용 가능한 함수가 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를 만들었다는 뜻이다.
      이렇게 만든 instance는 name, age, job에 값이 들어가있는 상태라는것을 볼 수 있다.
  • get은 무조건 1개만 가지고 올수있다. (0개, 2개 등은 에러가 난다)

2) all은 Person 테이블에 있는것 전부 가지고 오는 것.

3) filter

  • 조건을 넣지 않으면 all와 똑같이 모두 가져오게 된다.
  • 조건에 맞는 instance가 없으면 empty Query Set을 반환한다. <QuerySet []> (빈 리스트)
    • .exists() 하면 False 반환된다 (정말 많이 씀!)
  • 조건이 맞는 instance가 1개여도 QuerySet 안에 있다. (get와의 차이)
  • , 로 구분하여 여러가지 조건을 넣을 수도 있다. (field에서는 ,=and)

중요 차이: get은 object를 바로 불러오지만(개별 객체) all, filterQuerySet을 불러온다.

QuerySet = 객체object들이 담긴 List

  • 요소 하나하나가 ,로 구분이 되고
  • ⭐️ Indexing이 가능하다!! ⇒ 원하는 것을 불러올 수 있다
  • ⭐️ for문도 돌릴 수 있다!! ⇒ for문이 돌때마다 객체를 하나씩 꺼내서 가공하는걸 많이 쓴다

💡 Read 함수 변수에 저장

person = Person.objects.filter(age=33) 처럼,
명령어를 변수에 담을 수 있다!

여기서

person[0].name

소문자 personQuerySet 데이터 타입이기 때문에 (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

📢📢 Update하는 방법 2가지:

1) Update 함수 사용
2) Save 메소드 사용

💡 update()

Person.objects.filter(age=33).update(job="Firefighter")

filter로 QuerySet을 불러온 상태에서 사용 가능. 수정하고 싶은 대상이 정해져 있고, 뒤에 update를 할때 사용한다.
조건에 맞는 여러개의 값을 한번에 바꿀 수 있기 때문에 편하다.

💡 save()

객체를 불러와서 객체에 직접적으로 영향을 줌. (하나에만)
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

.delete 사용

  • row를 지우는것!
    • 만약 특정 사람의 job만 바꾸고 싶다면, delete말고 값을 사용해야한다. delete는 그 사람 자체를 없애는 것이기 때문이다. (그 사람의 name, age, job 다 한꺼번에 지운다고 생각하면 된다)
  • 삭제할 대상이 정해져 있어야 함. QuerySet을 불러오든,객체를 불러오든 상관없다.
    • 다만 QuerySet불러오면 여러개를 한번에 지우고, 객체를 불러오면 그 객체 하나만 지운다.
  • 테이블 row를 지워도 고유한 id는 남아있다. 주민등록번호가 사람이 죽으면 대체되지 않는것과 같은 원리이다.

여러가지가 있는데, 사용했을 때 어떤 결과/반환값이 나오는지,
반환값이 QuerySet인지 그냥객체인지 아는것이 중요하다.
ex. count()는 숫자를 반환한다. (filter()로 조건을 찾은 다음에 이 조건을 찾았을때 나오는 객체가 몇개인지 count()써서 숫자로 나타낼 수 있다.)
ex2. exists()는 Boolean(T/F)를 반환한다.
ex3. values()는 QuerySet이 나오긴 하는데, 객체가 아니고 dictionary들이 나온다.


Foreign Key

menu = models.ForeignKey('Menu', on_delete=models.CASCADE)

  • Foreign Key를 지정하면, Django가 알아서 "_id"를 분여준다.
  • IntegerField로 알아서 지정해준다
  • 'Menu'라는 field를 바라볼것이라는 뜻 ⇒ class Menu 데이터의 id가 앞에 변수 menu에 들어온다는 뜻.
  • 대문자 'Menu'를 쓰지 않고 위에 import문을 배제하고 file.class 이렇게 경로 그대로 쓰는 방법을 쓸수도 있다. circular dependency 라는 문제가 생길 수 있다.
  • Foreign Key는 해당 객체를 가르키기 때문에, ForeignKey로 만들어진 속성을 연결했을때, 해당 객체가 나온다.
    • 아래 캡쳐에서 product.name'아아'를 반환하는데, product.category<Category: Category object (2)>= object 를 반환하는걸 볼 수 있다.
    • 추가로, 객체이기 때문에 .를 이용해서 타고타고 들어갈 수 있다 - 아래 캡쳐처럼 다시 이름을 뽑을 수 있다

0개의 댓글