Skip to content

Django ORM #

Find similar titles

8회 업데이트 됨.

Edit
  • 최초 작성자
  • 최근 업데이트
    jwseo

Structured data

Category
Programming

Django ORM #

Django란 Python 기반의 웹 프레임워크로 자세한 내용은 여기를 참고하면 된다.
ORM이란 Object-Relational Mapping의 약자로 객체(Object)와 관계형 데이터베이스(Relational Database)의 데이터를 매핑(Mapping)해주는 것을 의미한다. 객체 간의 관계를 바탕으로 SQL을 자동 생성하여 sql쿼리문 없이도 데이터베이스의 데이터를 다룰 수 있게 해준다.
데이터베이스의 테이블을 객체지향 프로그래밍에서 흔히 사용하는 객체(Class)처럼 사용할 수 있도록 해주는 기술이다.
기존 쿼리문을 작성하여 데이터베이스를 조작하는 것을 넘어서서 더 효율적이고 가독성 및 유지 보수에 적합한 코드를 만들기 위해 나온 기술이다.

예시 #

  • book 이라는 객체에서 저자의 이름이 kim 인 책 목록을 가져오고 싶을 때,

    1. SQL 쿼리문을 사용할 경우

      book_list = new list();
      sql = "SELECT book FROM library WHERE author = 'kim'";
      data = query(sql);
      while (row = data.next()){
          book = new Book();
          book.setAuthor(row.get('author'));
          book_list.add(book);
      }
      

      sql 쿼리문을 작성하고, 데이터를 가져오는 일련의 모든 과정들을 코드에 적어야 한다.

    2. ORM을 사용할 경우

      book_list = BookTable.query(author="kim")
      

    간단하게 한 줄로 원하는 객체를 가져올 수 있다.

ORM 활용 #

  1. 데이터 가져오기

    • objects.all()

      >>> Book.objects.all()
      <QuerySet [<Book: one>, <Book: two>]>
      

    Book객체에 저장된 데이터를 모두 가져올 수 있다.

    • objects.get()

      >>> Book.objects.get(author='kim')
      

    get()은 조건에 해당하는 오직 하나의 객체만을 반환한다. 반환되는 객체가 하나인지 확실히 알 수 있는 경우에만 사용해야 한다. 만약 하나 이상의 객체가 조회되면 MultipleObjectsReturned 에러를 발생시키므로 유의한다. get()은 속성(property)을 가지고 있으므로, 하단과 같이 객체의 컬럼에 대한 정보를 바로 가져올 수 있다.

        >>> book = Book.objects.get(pk=1)
        book.title
        book.author
    
  2. 데이터 추가하기

    • objects.create()

      >>> Book.objects.create(title='Developer', author='hyelyn')
      

    데이터 모델 Book객체에 정의된 title과 author 필드에 데이터를 넣어 새로운 데이터를 추가할 수 있다.

    • ()

      >>> book = Book()
      >>> book.title = 'Hyelyn Potter'
      >>> book.author = 'hyelyn'
      >>> book.save()
      
  3. 데이터 검색

    • objects.filter()

      >>> Book.objects.filter(author='heylyn')
      <Queryset [<Book: one>, <Book: two>]>
      

    filter의 반환 값을 쿼리셋(Queryset)이라는 Django ORM에서 발생한 자료형이다. 쿼리셋은 데이터베이스에서 전달받은 객체들의 목록을 담고있다. 리스트 구조와 같아서 리스트 사용하는 것과 같이 사용할 수 있디. 속성(property)뿐만 아니라 메서드(method)도 가지고 있다. 여러 레코드를 다루므로 반복(iterate), 슬라이싱(slicing), 필터링(filtering)을 할 수 있는 메서드가 필요하다. get()과 다르게 객체의 컬럼을 바로 가져올 수 없다. filter()를 통한 결과가 단 하나만 나오더라도, filter() 사용 결과는 QuerySet으로 반환되기 때문이다. 만약 filter() 메서드로 가져온 쿼리셋에서 단일 레코드에 대한 접근이 필요한 경우, 하단과 같이 적절한 메서드를 사용하여 레코드를 추출한 다음에 해당 레코드의 속성을 가져와야 한다.

        >>> book = Book.objects.filter(author='john)'.first()
        Book.objects.filter(author='john)'.last()
    
  4. 데이터 삭제

    • objects.delete()

      >>> d = Book.objects.get(title='Developer')
      >>> d.delete()
      # 삭제 완료.
      

Django ORM이 실행하는 실제 SQL 질의문 확인하는 방법 #

django ORM을 활용하여 데이터를 다루는 것이 편할 수는 있지만, 데이터에 대해 이해하고 더 잘 다루기 위해서는 SQL 질의문이 어떤 식으로 데이터를 다루는지 확인하고 ORM을 사용하면 더 효과적으로 사용할 수 있다.

django에서 SQL 질의문을 구하는 것은 간단하다.

Book이라는 모델이 있고 이 모델의 모든 행을 읽어올 때 Book.objects.all() 과 같은 코드를 작성하면 된다. 이렇게 구한 쿼리셋을 내장 함수인 querystr형태로 출력하면 SQL 질의문을 확인할 수 있다.

    >>> queryset = Book.objects.all()
    >>> str(queryset.query)
    SELECT "appname_book"."id", "appname_book"."title","appname_book"."author"
    FROM "appname_book"

Django ORM으로 연산하는 방법 #

  1. OR
    OR연산으로 여러 조건 중 하나라도 만족하는 행을 구해야 하는 경우가 있다. 예를 들어 Book 데이터베이스 중 title이 A이거나 B인 데이터를 구해야 한다면 다음과 같은 방법을 사용할 수 있다.

    • queryset_1 | queryset_2

      >>> queryset = Book.objects.filter(title="A")| Book.objects.filter(title="B")
      
    • filter(Q(<condition_1>|Q(<condition_2>)
      Q 사용 시 모듈을 import 해야 한다.

      >>> from django.db.models import Q
      >>> Book.objects.filter(Q(title="A") | Q(title="B"))
      
  2. AND
    AND 연산으로 여러 조건을 모두 만족하는 행을 구해야 하는 경우는 다음과 같은 방법으로 사용할 수 있다.

    • filter(<condition_1>, <condition_2>)

      >>> queryset = Book.objects.filter(title="A", title="B")
      
    • queryset_1 & queryset_2

      >>> queryset = Book.objects.filter(title="A") & Book.objects.filter(title="B")
      
    • filter(Q(<conditione_1>) & Q(<condition_2>))

      >>> from django.db.models import Q
      >>> queryset = Book.objects.filter(Q(title="A") & Q(title="B"))
      
  3. NOT
    Book 모델의 데이터베이스 중 title이 'A'가 아닌 데이터가 필요한 경우 다음과 같이 구할 수 있다.

    • exclude(<condition>)

      >>> queryset = Book.objects.exclude(title="A")
      
    • filter(~Q(<condition>))

      >>> from django.db.models import Q
      >>> queryset = Book.objects.filter(~Q(title="A"))
      

Django ORM으로 다양한 조건의 데이터 가져오기 #

  1. count()
    해당 쿼리셋에 속하는 객체의 개수를 반환한다.

    • Book 모델에서 저자가 'Kristin'인 책의 수

      >>> Book.objects.filter(author='Kristin').count()
      
  2. exists()
    해당 쿼리셋에 속하는 객체가 존재하는지를 반환하며, 반환되는 값은 True 또는 False이다.

    • Book 모델의 title이 python을 포함하는 QuerySet

      >>> Book.objects.filter(published_date__gte='2023-01-01').exists()
      
  3. contains()
    지정한 문자열을 포함하는 QuerySet을 반환한다.

    • Book 모델의 title이 python을 포함하는 QuerySet

      >>> Book.objects.filter(title__contains=’python’)
      
  4. order_by(*fields)
    지정된 필드 기준으로 정렬된 QuerySet을 반환한다.

    • Book 모델에서 출판일자가 오름차순(오래된 순)으로 정렬된 QuerySet

      >>> Book.objects.order_by('published_date')
      
    • published_date 앞에 -를 붙이면 내림차순(최신순)으로 정렬된 QuerySet

      >>> Book.objects.order_by('-published_date')
      
  5. range()
    지정한 범위의 QuerySet을 반환한다. sql의 between과 같은 기능을 한다.

    • Book 모델의 id의 범위가 1부터 10까지인 QuerySet

      >>> Book.objects.filter(id__range=(1,10))
      

이 외의 기능들에 대해서는 django 공식문서 참조를 권장

ORM의 장점 #

  • SQL query가 아닌 직관적인 코드로 (메소드) 데이터를 조작할 수 있어 개발자가 객체모델로 프로그래밍하는 데 집중할 수 있다.
  • 각 객체에 대한 코드를 별도로 작성하기 때문에 코드 가독성이 좋다.
  • SQL의 절차적이고 순차적인 접근이 아닌 객체 지향적인 접근으로 생산성이 좋다.

ORM의 단점 #

  • 프로젝트 복잡성이 커질 경우 난이도가 높아진다.
  • 잘못 구현하게 되면 속도가 저하되고 일관성이 없어질 수 있다.
  • sql 쿼리문으로 다루지 않다 보니 정확한 원리를 이해하는데 어려움이 발생할 수 있다.

참고문헌 #

  1. ORM(Object-Relational Mapping)이란?

  2. [Django] ORM and Querysets

  3. Django ORM cookbook

0.0.1_20240214_1_v81