Lina's Toolbox

Django ORM 본문

 

ORM (Object-Relational-Mapping)

  • SQL 안쓰고 Python으로 데이터베이스 조작할 수 있게 해주는 것!
    (ORM은 최적화된 sql쿼리를 내부에서 제공해주기 때문에 기초 sql을 할수 있는 정도라면 orm 쓰는게 더 빠르다.)

  • Django ORM만 있는건 아니고 여러 가지가 존재합니다.
    • Python - Django ORM, SQLAlchemy, Tortoise ORM …
    • JAVA - JPA, Hybernate
    • Node.js - Sequalize …

결국 ORM이 중간에서 고생해 주는 것!

  • SQL Statement ↔ ORM ↔ Python Object 

 

ORM 장단점

 

💡 장점

  1. SQL을 잘 알지못해도 DB 조작 가능!
  2. SQL을 알아도 기존의 복잡한 쿼리문 작성없이 객체 지향적인 접근 가능!
  3. SQL을 잘사용하지 못한다면 ORM이 변환해주는 것이 더 빠름!
  4. 생산성⬆️

💡 단점

  1. ORM에서 지원하지 않는 쿼리라면 직접 작성해야함
  2. 서비스가 커질수록 ORM만으로는 한계가 있을 수 있음
  3. 매우 효율적인 SQL을 작성하고 싶다면 ORM이 불편할 수 있음

→ 현재의 개발은 대기업 정도의 규모가 아니라면 생산성이 정답인 경우가 많다. 

→ ORM을 써야한다.


Database API

✔️ 파이썬에서 데이터 베이스를 사용하려면 어떻게 해야할까?

 

database api

  • 다른말로 database-abstraction API 라고도 합니다.
  • 쉽게말해 Django ORM으로 Database API를 사용해서 데이터베이스를 조작하는 것입니다.

 

Manager

  • 우리가 모델 클래스를 생성하면 Django는 자동적으로 CRUD 할 수 있는 Database API를 제공합니다.
  • 그리고 집사를 한명 붙여주는데 그게 바로 Manager
    • 정식 이름은 Django ORM Manager인데 하는일은 우리가 작성한 모델 클래스를 이용하여 데이터 베이스 쿼리작업을 도와주는 역할을 합니다.
  • 우리는 Manager를 이용해서 Django ORM의 Queryset API를 사용하게 될 것입니다.
    • Queryset == ORM을 사용해서 데이터베이스로부터 전달받은 객체입니다.
  • 이 매니저의 기본(default)이름은 objects 입니다.

 

기본 형태 

       MyModel.objects.all()

  • Model Class . Manager . QuerysetAPI

CRUD with Shell

  • Django가 제공하는 여러가지 기능을 명령어로 입력해서 실행해볼 수 있는 Shell 환경을 말합니다.

그런데 우리가 Python 파일을 실행할 때는

  • python shell은 python 만 입력하면 되는데 🤔
  • 근데 django는 어떤 파일을 실행해야하지?
    • manage.py 도 결국에는 그 파일자체가 아니라 여러가지 환경을 열어주는 것입니다.
    • 즉, django 프로젝트 환경이 필요합니다!
    == python manage.py shell 현재 Django 프로젝트 환경을 Shell로 접근할 수 있게 해줍니다.

 

사전 셋팅

그냥 Shell 열기

python3 manage.py shell

여기서 만약 우리가 작성한 Articles의 Article Model 클래스를 가져오고 싶다면

 

 

  • 데이터를 사용하고싶으면 데이터를 먼저 불러와야함 → from articles.models import Article
  • 모델이 한두개도 아니고, 프로젝트를 하다보면 모델이 엄청 많을텐데, 이런 식으로 사용하기는 너무 불편합니다.
  • 자동완성도 사용할 수 없습니다.

 

패키지 설치

  • django-extensions
pip install django-extensions
  • Django 기본 Shell보다 더 많은 기능이 있는 shell_plus를 제공하고 있습니다.
  • 아직 한 가지 설정이 더 필요합니다

 

settings.py 앱 등록

🚨django_extensions, 처럼 중간에 하이픈(-)이 아닌 언더바(_)로 작성해야한다는 것 주의해주세요!

exit()하여 쉘 빠져나올 수 있다.

 

 

 

ipython

pip install ipython
  • ipython은 python 기본 Shell에 여러가지 기능을 더한것입니다.
  • 예를 들어 자동완성, 코드 색상 강조와 같은 기능이 있습니다.

 

패키지 설치했으니 뭐다?

pip freeze > requirements.txt

패키지를 새로 설치 했으므로 requirements.txt에 추가해주기!

 

 

설치가 끝났으면 실행해보자 

이제 패키지를 설치해주었으므로, 쉘을 실행할 때 shell_plus를 해줄수 있다.

→ 우리 프로젝트에있는 모든 모델 클래스를 import해줬다. 많이 쓰는 것들도 임포트 이미 해줬다!

python3 manage.py shell_plus

이제 셋팅이 끝났으니 여기서 직접 입력해보며 Django ORM을 실습할 수 있다.


CRUD

  • 우리가 사용하는 서비스의 대부분이 CRUD로 이루어져 있습니다.
  • Create, Read, Update, Delete
  • 게시글을 작성하고(Create) 조회하고(Read) 수정하고(Update) 삭제합니다(Delete)
    • 대부분의 소프트웨어가 하는일입니다.

(1) 전체 Article 조회하기

Article.objects.all()

아직 따로 무언갈 만들지 않았다면 조회결과가 비어있는 게 정상입니다.

 

(2) Article을 생성하는 다른 방법

article = Article(title='second_title', content='my_content')
article.save()

 

(3) 하나의 Article 생성하기

article = Article()
article.title = 'first_title'
article.content = 'my_content'

# 여기에서 전체 Article을 조회해보면
Article.objects.all() # 비어있다

# save()하기전에는 저장되지 않음
article.save()

# 다시 전체 Article을 조회해보면 하나의 아티클이 있음
Article.objects.all()


# 속성 하나씩 접근하기
# 제목 
article.title

# 내용
article.content

# 생성일시
article.create_at

# pk(id)
article.id

 

(4) Article을 생성하는 또 다른 방법

Article.objects.create(title='third title', content='마지막 방법임')
# save()가 필요하지 않음

 

(참고) __str__ 사용하기

class Article(models.Model):
    title = models.CharField(max_length=50)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.title
  • Article Object 보다 파악하기 쉽습니다.
  • Article Class를 문자열 취급했을 때 처리하는 로직을 작성할 수 있습니다.
💡 __str__
어떠한 클래스를 마치 문자열처럼 취급했을 때 어떻게 보여질지를 결정하는 매직매서드
→ 모델 클래스에서 __str__메소드를 만들었다. 마이그레이션 만들고 마이그레이션을 해줘야할까?
놉! 마이그레이션은 데이터베이스에 변경사항이 생길때만
이건 데이터베이스에 조작이 x , 파이썬에서 클래스의 코드
 makemigration 하고 migrate해도 아무일도 일어나지 않음
 쉘 exit으로 껐다 킨후
 Articles.objects.all() 해보면 출력형태 바뀐것 확인할 수 있다!

 

 

(5) 모두 조회하기

Article.objects.all()

조회 결과는 Queryset으로 반복가능한 객체 형태입니다.

📌 QuerySet
- 데이터베이스에서 조회한 목록들
- 리스트처럼 순서가 있어서 인덱스로 접근 가능 → iterable(반복문에 활용 가능)

 

 

(6) 하나만 조회하기

Article.objects.get(id=1)
  • 딱 1개의 조회가 필요할 때 사용합니다.
  • 조건에 해당하는 객체가 없다면 DoesNotExist 예외를 발생시킴 (터진다는 소리)
  • 한 개 이상의 객체가 리턴될 경우도 MulipleObjectReturned 예외를 발생시킴 (터진다는 소리)
Article.objects.get(content='my_content') # 두개 리턴되어 에러

Atricle.object.get(조건) → QuerySet 형태가 아닌 오브젝트가 그대로 튀어나온다!!!

 

(7) 조건으로 조회하기

Article.objects.filter(content='my_content')
  • lookup과 일치하는 객체를 모두 리턴합니다.
    조건에 사용되는 매개변수를 lookup 이라고합니다.
  • 당연히 굉장히 다양한 lookup을 django는 제공

업데이트 할때는 꼭 get()만 사용해야하나요?

→ 놉! filter로 리스트가 나온다면, for문을 돌려서 다 바꿔줄수 있다!

Article.objects.filter(id__gt=2) # 2보다 큰 id
Article.objects.filter(id__in=[1,2,3]) # 1,2,3에 속하는 id
Article.objects.filter(content__contains='my') # content에 'my'가 포함된
...

일치하지 않는다면 빈 쿼리셋을 리턴합니다.

 

📌 공식문서 참조 : https://docs.djangoproject.com/en/4.2/topics/db/queries/#field-lookups

 

 

(8) 수정하기

  • 수정하기는 아래의 단계를 따릅니다.
    1. 수정할 객체를 조회
    2. 수정할 내용을 입력
    3. 수정한 것을 데이터베이스에 반영
article = Article.objects.get(id=1)
article.title = 'updated title'
article.save()

 

 

(9) 삭제하기

article = Article.objects.get(id=2)
article.delete()