본문 바로가기

Python/Django

Django ORM과 QuerySet

잘 모르니까. 모르는게 많으니까 공부.

ORM이란? 

Object Relational Mapping 의 줄임말로 객체(Object) 와 데이터베이스의 데이터(Relational)를 연결(Mapping)해주는 개념 

개발자가 별도의 SQL 쿼리를 짤 필요 없이 코드 작성만으로 DB를 조작할 수 있게 해주는 개념으로 장고만 있는게 아니라 다양한 언어/프레임워크 등에서 사용 되는 개념이다. 

 

DB 쿼리의 경우 테이블 생성시 아래와 같이 작성 된다면, 

CREATE TABLE `tutorials` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`usernm` VARCHAR(50) NOT NULL,
	`email` VARCHAR(255) NOT NULL,
	`updated_dt` DATETIME(6) NULL DEFAULT NULL,
	PRIMARY KEY (`id`) USING BTREE,
)

 

Django 의 ORM은 다음처럼 생성한다 (심지어 DB 버전/종류만 맞으면 ID 는 자동생성!) 

from django.db import models

class tutorials(models.Model):
    usernm = models.CharField(max_length=50, unique=False)
    email = models.EmailField(max_length=255, unique=False)
    telno = models.CharField(max_length=15, unique=False, null=True)
    updated_dt = models.DateTimeField(blank=True, null=True, auto_now=True)

 

Queryset 이란?

Django 의 ORM을 사용하여 Database와 소통할때 발생하는 자료형.

마치 list 와 매우 비슷한데 데이터베이스의 데이터가 list 처럼 Queryset 안에 들어오는 형태이다. 

QuerySet[Database data]

Queryset을 사용하고자 하면, 먼저 아래 명령어를 통해 터미널에서 shell을 실행 한다. 

>>> python manage.py shell

 

database를 모델을 통해 조작하므로 모델을 가져오면 Queryset을 통해 데이터를 가져올 준비가 된 상태이다.

>>> from test.models import tutorials

 

아래 명령어는 해당 쿼리셋의 모든 요소를 반환하라는 (테이블의 데이터 전체를 가져오는) 명령인데, 

Django의 lazy한 특성 때문에 아래 명령어 실행 시에도 실제로 DB에 Query 가 이뤄지진 않는다.

>>> data = tutorials.objects.all()

 

아래와 같이 실제로 필요시에만 데이터를 가져오게 된다(fetch)

>>> data
<QuerySet [<tutorials: tutorials object (1)>, <tutorials: tutorials object (2)>, 
<tutorials: tutorials object (3)>, '...(remaining elements truncated)...']>

 

django-extensions 을 통해 DB 쿼리 수행 시점을 확인 가능하다

로딩에 대한 부분은 다음시간에 다시 정리! 

 

Queryset 접근 방식 

Queryset은 Dictonary 형태로 반환 된다. 

이 Dictonary 형태는 model 객체의 Key를 통해 객체를 표현 할 수 있다. 

# Blog object를 포함하는 list
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>

# dictionary를 포함하는 list
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>

 

- value() 메소드는  dictionary의 key와 value에 접근이 가능하다.

>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>

>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

 

- Queryset()은 리스트 형태로[index] 의 형태로 접근이 가능하다. 

>>> data = tutorials.objects.all()
>>> data[0]
<QuerySet [<tutorials: tutorials object (1)>]>

Queryset Method 소개 

.all()

현재 QuerySet(또는 QuerySet 하위 클래스)의 복사본을 반환한다. 테이블 데이터의 전체를 가져온다.

>>> data = tutorials.objects.all()
>>> data
<QuerySet [<tutorials: tutorials object (1)>, <tutorials: tutorials object (2)>, 
<tutorials: tutorials object (3)>, '...(remaining elements truncated)...']>

.values()

Queryset 내부의 value값으로 전체 데이터를 모두 가져온다

>>> data = tutorials.objects.values()
>>> data
<QuerySet [{'id': 1, 'usernm': 'OOO', 'email': 'OOO@naver.com', 'telno': '02-0000-0000',  
'updated_dt': datetime.datetime(2022, 10, 11, 16, 4, 27, 799937, tzinfo=<UTC>)}, 
{'id': 2, 'usernm': 'AAA',  'email': 'AAAA@naver.com', 'telno': '02-1111-1111', 
'updated_dt': datetime.datetime(2022, 10, 11, 16, 4, 27, 800502, tzinfo=<UTC>)}]>

.filters()

인수로 필드명 = 조건값이 들어가며 특정 데이터로 필터링된 데이터를 가져온다.

#1
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>

#2
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>

 

2개 이상의 인수 필요시:  and : 별도 명시 없음 /  or : Q 사용 

from django.db.models import Q
# AND와 OR 함께 사용시 
Poll.objects.get(
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
    question__startswith='Who',
)

# INVALID QUERY
Poll.objects.get(
    question__startswith='Who',
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

.get()

필드명 = 조건값 을 인수로 해당하는 데이터가 1개인 경우 사용 가능. 

0개 이거나(DoesNotExist) 2개 이상(MultipleObjectsReturned)이면 에러 발생

Entry.objects.get(id=1)
Entry.objects.get(Q(blog=blog) & Q(entry_number=1))

 

하나만 존재할 거라 예상하는 경우 get에 인수없이 사용 가능 

Entry.objects.filter(pk=1).get()

 






참고사이트 : 
https://docs.djangoproject.com/en/4.1/ref/models/querysets/#all

https://velog.io/@magnoliarfsit/ReDjango-7.-ORM%EA%B3%BC-Queryset

https://velog.io/@rosewwross/session-note

https://kgu0724.tistory.com/88

https://docs.djangoproject.com/en/4.1/ref/models/querysets/#values

https://docs.djangoproject.com/en/4.1/topics/db/queries/#complex-lookups-with-q