ORM & Queryset

Seoyul Kim·2020년 5월 6일
1

Django

목록 보기
8/12

Query와 database layer

  • 장고에서는 여러 종류의 데이터를 데이터베이스 종류와는 독립적인 형태로 객체화 한다.(ORM)

ORM이란?(Object Relational Mapping)

  • OOP 언어와 데이터를 다루는 RDBMS 와의 상이한 시스템을 매핑하여, 데이터 관련 OOP 프로그래밍을 쉽게 하도록 도와주는 기술
  • Model Class를 통해서 객체를 만들고 이 객체를 통해서 DB에 접근한다.

QuerySet이란?

>>> from .models import Book
>>> Book.objects.all() # Book 모델(테이블)의 모든 데이터를 가져오기
<QuerySet [<Book:  제목1>, <Book:  제목2>]>
  • objects: Model Manager, DB와 Django Model 사이의 Query Operation(질의 연산) 인터페이스 역할
  • objects를 사용하여 다수의 데이터를 가져오는 함수를 사용할 때 반환되는 객체가 QuerySet이다.

QuerySet 합치기

  • | 를 이용한다.(같은 모델에서 나온 쿼리셋만 가능)
q3 = q1 | q2
  • 이외에도 쿼리셋 간의 합집합, 교집합, 차집합을 만들수 있는 메소드가 있다.(intersection(), difference())

race condition 피하기

  • 쿼리 표현식을 통해서 코드들의 경합상황을 피한다.

    경합 상황이란?

    • 다중 프로그래밍 시스템이나 다중 처리기 시스템에서 두 명령어가 동시에 같은 기억 장소를 액세스할 때 경쟁에 의해 수행 결과를 예측할 수 없게 된다.
  • F() expression
    • 파이썬이 아닌 데이터베이스 자체 내에서 해당 조건을 비교하는 기능을 가진다.
    • 데이터베이스 수정이 일어나는 부분에는 F를 사용하면 레이스 컨디션 문제를 해결하고, 퍼포먼스 면에서도 이득이 된다.
selected_choice.votes += 1 
#실행시 데이터베이스의 값을 참조 -> 메모리에 로딩 -> 연산 -> 결과값 데이터베이스에 저장

#single instance
select_choice.votes = F("votes") + 1 
#데이터베이스 자체에서 연산 -> 결과값 저장

#querysets of object instances
reporter = Reporters.objects.filter(name='Tintin')  
reporter.update(stories_filed=F('stories_filed') + 1)

데이터베이스 함수

  • UPPER(), LOWER(), COALESCE(), CONCAT(), LENGTH(), SUBSTR()
  • 쉽고 간결하며, 파이썬에서 데이터 처리속도보다 데이터베이스 내에서 데이터 처리속도가 빠르므로 성능이 향상된다.

인덱스 사용

  • 모델의 필드 옵션으로 db_index를 추가하면 해당 필드에 대해서 database index가 생성된다.

예외처리

get_object_or_404

  • 상세페이지 view에서는 get() 대신에 get_object_or_404()를 사용하면 예외 처리가 필요 없다.
  • 그 외의 경우에는 try-except를 이용한 예외처리가 필요하다.
>>> Book.objects.get(title="없는 책")
DoesNotExist: Book matching query does not exist.

>>> from django.shortcuts import get_object_or_404
>>> get_object_or_404(Book, title="없는 책")
Http404: No Book matches the given query.

objectDoesNotExist vs DoesNotExist

  • ObjectDoesNotExist: 모든 모델 객체에서 이용 가능하며 import가 필요하다.
  • DoesNotExist: 특정 모델에서만 이용 가능

MultipleObjectsReturned

  • 쿼리가 하나 이상의 객체를 반환할 수 있다면 MultipleObjectsReturned 예외처리를 통해서 에러로그를 남길 수 있다.

지연 연산

Lazy Evaluation(지연 연산)이란?

  • Lazy Evaluation을 활용하여 장고 코드를 더 깔끔하게 만들 수 있다.
  • 데이터가 정말로 필요하기 전까지는 장고가 SQL을 호출하지 않기 때문에 ORM 메소드와 함수를 얼마든지 연결해서 코드를 쓸 수 있다.
  • 한줄에 길게 쓰는 대신에 여러줄에 나눠 쓰면 가독성을 향상시키며, 유지 보수를 쉽게 해준다.

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)

제외 조건(exclude)

# 제목에 1을 포함하지만 3으로 끝나지 않는 record
Post.objects.filter(title__icontains='1').exclude(title__endswith='3')

OR 조건(filter)

  • complex lookups with Q objects: or 조건을 사용하기 위해서는 Q 객체 import 가 필요하다.
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 조건

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

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

슬라이싱

  • 역순 슬라이싱은 지원하지 않는다. 그럴 경우 먼저 특정 필드 기준으로 내림차순 정렬을 수행한 되 슬라이싱 한다.
queryset = queryset[:10]

지정 조건(get, first, last)

  • 지정 조건으로 DB로부터 데이터 fetch

queryset.get

  • 해당 조건에 해당되는 데이터가 1개일 때 정상 처리
  • 0개시 DoesNotExist 예외, 2개 이상일시 MultipleObjectsReturned 예외 발생

queryset.first(), queryset.last()

  • 지정 조건 내에서 첫번째 / 마지막 데이터 row를 fetch
  • 지정 조건에 맞는 데이터 row가 없다면 None을 반환한다.

DB 데이터 추가

  1. Model Manager의 create 함수를 통해 저장

  2. Model Instance의 save 함수를 통해 저장

DB 데이터 수정

  1. save() 함수를 통해 저장
  • 각 model instance 별로 SQL 수행하므로 다수 row에 대해서 수행시 성능이 저하된다
  1. queryset의 update 함수에 업데이트 할 속성값을 지정하여 일괄 수정
  • 하나의 SQL로서 동작하므로 동작이 빠르다
queryset.update(title='test title')

ref)https://wayhome25.github.io/django/2017/07/25/tsd7-django-query-database/

0개의 댓글