[Re:Django] 4. 장고 ORM을 사용해서 DB CRUD 구현하기

Magit·2020년 5월 4일
11

Django

목록 보기
4/13

장고 ORM이란?

ORM은 각 언어별로 있는 기능이다. 원래 데이터베이스 서버의 어떤 데이터를 조회, 추가, 수정, 삭제 등을 할 때는 sql이라는 언어를 써야된다. 그런데 sql을 사용하지 않고, 파이썬이라면 파이썬 코드로, 자바면 자바로, 각 언어 그대로를 활용해서 sql 코드를 만들어내는 라이브러리가 있다. 그걸 ORM 이라고 한다. 장고에서는 Django Model 이 장고의 ORM이다.

Model Manager

  • 데이터베이스 질의 인터페이스를 제공한다.
  • 디폴트 Manager로 모델클래스.objects 를 제공한다.
  • Model Manager를 통해서 해당 모델 클래스의 DB 데이터를 추가, 조회, 수정, 삭제(CRUD) 가능하다.

QuerySet

  • SQL을 생성해주는 인터페이스
  • queryset을 통하여 별도로 SQL을 작성할 필요 없이 DB로 부터 데이터를 가져오고 추가, 수정, 삭제가 가능하다.
  • Model Manager를 통해서 해당 Model에 대한 QuerySet을 획득한다.
    • Post.objects.all() : “SELECT * FROM post…” 와 같은 SQL문 생성
    • Post.objects.create() : “INSERT INTO post VALUES(…)” 와 같은 SQL문 생성
  • Chaining 을 지원 : QuerySet 수행 리턴값이 다시 QuerySet
  • connection 모듈을 통해 queryset으로 만들어진 실제 sql문을 shell에서 확인할 수 있다.


DB CRUD 구현하기

장고에서 ORM을 통해서 CRUD를 구현하는 것에 대해서 알아보자.

DB 데이터 추가 (Create)

  • 필수 필드를 모두 지정하고 데이터 추가가 이뤄져야한다.(필드 정의 시에, blank=True, null=True 혹은 디폴트값이 지정되지 않은 필드) 그렇지 않으면 IntegrityError 예외가 발생
  • shell 을 통해서 모델을 import한 후 모델명?? 명령어를 치면 상세 필드 옵션을 확인할 수 있다.

방법1. 각 Model Instance의 save 함수를 통해 저장

model_instance = Post(author=User.objects.all()[0], title='title', text='content')
model_instance.save()  

방법2. 각 Model Instance의 create 함수를 통해 저장

new_post = Post.objects.create(author=User.objects.get(id=1), title='title', text='content')
  • .save() 와 .create() 실행시 DB에 INSERT SQL이 전달된다.

DB 데이터 조회 (Retrieve)

AND 조건 (filter)

  • chaining, Lazy
# chaining을 통해 조건1~3 이 적용된 queryset을 마지막에 리턴
queryset = 모델클래스명.objects.all()
queryset = queryset.filter(조건필드1=조건값1, 조건필드2=조건값2)
queryset = queryset.filter(조건필드3=조건값3)


for model_instance in queryset:
    print(model_instance) # 화면에 출력할 때 DB에 쿼리 (lazy)
  • i = ignore_case (대소문자 구별 X)
# 필터링 (qs1 = qs2)
qs1 = Post.objects.filter(title__icontains='1', title__endswith='3') # i = ignore_case (대소문자 구별 X)
qs2 = Post.objects.filter(title__icontains='1').filter(title__endswith='3') # 체이닝

OR 조건 (filter)

from django.db.models import Q

모델클래스명.objects.all().filter(Q(조건필드1=조건값1) | Q(조건필드2=조건값2)) # or 조건
모델클래스명.objects.all().filter(Q(조건필드1=조건값1) & Q(조건필드2=조건값2)) # and 조건
  • blog.views.post_list 뷰에서 간단한 검색 구현
def post_list(requests):
    qs = Post.objects.all()   # Post 모델클래스의 전체 데이터 저장
    q = requests.GET.get('q','')   # get파라미터중 q라는 값 저장
    if q:        # 만약 값이 있을 경우
        qs = qs.filter(title__icontains=q)  # 대소문자 구별없이, title에 값을 찾는다.
    return render(requests, 'blog/post_list.html', {
        'post_list' : qs,  
        'q':q,})   


#blog/templates/blog/post_list.html
<form action="" method="get">
    <input type="text" name="q" />
    <input type="submit" value="검색" />
</form>

특정필드 기준 정렬조건 (Meta.ordering)

  • queryset의 기본 정렬은 모델 클래스 내부의 Meta.ordering 설정을 따른다.
# myapp/models.py
#
class Post(models.Model):
  ....
  class Meta:
    ordering = ['-id'] # id 필드 기준 내림차순 정렬, 미지정시 임의 정렬
  • 모델 Meta.ordering 을 무시하고 직접 정렬조건 지정도 가능하다.
ordering = ['pub_date'] # 지정 필드 오름차순 요청
ordering = ['-pub_date'] # 지정 필드 내림차순 요청
ordering = ['-pub_date', 'author'] # 1차기준, 2차기준

범위 조건 (슬라이싱)

queryset = queryset[:10] # 현재 queryset에서 처음10개만 가져오는 조건을 추가한 queryset
queryset = queryset[10:20] # 현재 queryset에서 처음10번째부터 20번째까지를 가져오는 조건을 추가한 queryset

# 리스트 슬라이싱과 거의 유사하나, 역순 슬라이싱은 지원하지 않음
queryset = queryset[-10:] # AssertionError 예외 발생

# 이때는 먼저 특정 필드 기준으로 내림차순 정렬을 먼저 수행한 뒤, 슬라이싱
queryset = queryset.order_by('-id')[:10]

지정 조건 (get, first, last)

  • 지정 조건으로 DB로부터 데이터 Fetch
  • queryset.get
    • 해당 조건에 해당되는 데이터가 1개임을 기대
      • 0개 : 모델클래스명.DoesNotExist 예외 발생
      • 1개 : 정상처리
      • 2개 : 모델클래스명.MultipleObjectsReturned 예외 발생
# 지정 조건의 데이터 Row를 순회
for model_instance in queryset:
    print(model_instance)

# 특정 조건의 데이터 Row 1개 Fetch (1개!! 2개이상말고 1개!! 0개말고 1개!!) model_instance = queryset.get(id=1)
model_instance = queryset.get(title='my title')
  • queryset.first(), queryset.last()
    • 지정 조건 내에서 첫번째/마지막 데이터 Row를 Fetch
    • 지정 조건에 맞는 데이터 Row가 없더라도, DoesNotExist 예외가 발 생하지 않고, None을 반환
model_instance = queryset.first() # model instance 또는 None
model_instance = queryset.last() # model instance 또는 None

DB 데이터 수정 (Update)

방법1. 각 Model Instance 속성을 변경하고, save 함수를 통해 저장

  • 각 Model 인스턴스 별로 SQL 수행
  • 다수의 Row에 대해서 수행 시 성능저하
post_instance = Post.objects.get(id=66)
post_instance.title = 'edit title' # title 수정
post_instance.save()

queryset = Post.objects.all()
for post in queryset:
    post.tags = 'Python, Django'
    post.save() # 각 Model Instance 별로 DB에 update 요청 - 성능저하

방법2. QuerySet의 update 함수에 업데이트할 속성값을 지정하여 일괄 수정

  • 하나의 SQL 로서 동작하므로 동작이 빠르다.
queryset = Post.objects.all()
queryset.update(title='test title') # 일괄 update 요청

DB 데이터 삭제 (Delete)

방법1. 각 Model Instance의 delete 함수를 호출하여 삭제

  • 각 Model 인스턴스 별로 SQL 수행
  • 다수의 Row에 대해서 수행 시 성능저하
post_instance = Post.objects.get(id=66)
post_instance.delete()

queryset = Post.objects.all()
    for post in queryset:
    post.delete() # 각 Model Instance 별로 DB에 delete 요청 - 성능저하

방법2. QuerySet의 delete 함수를 호출하여, 관련 데이터 삭제

  • 하나의 SQL 로서 동작하므로 동작이 빠르다.
queryset = Post.objects.all()
queryset.delete() # 일괄 delete 요청

참조 블로그
초보몽키의 개발공부로그
7. 모델을 통한 데이터 CRUD

profile
이제 막 배우기 시작한 개발자입니다.

0개의 댓글