본문 바로가기

Django

Django CRUD - QuerySet API

$ python manage.py shell

이 쉘은 장고를 통해 연 쉘이라 장고는 이미 import되어 있다. models.py 내의 필요한 class를 import해야 된다.

>>> from <app명>.models import <모델 class명>

이렇게 import하고 나면 해당 class들을 사용할 수 있다.

CRUD (Create, Retrieve, Update, Delete)

데이터를 처리하는 4가지(생성, 조회, 업데이트, 삭제) 방식이다.

장고의 DB는 장고가 제공하는 ORM을 사용해 Model의 class 기반 객체로 맵핑할 수 있다. View에서 QuerySet method를 이용해 작성한 로직대로 이 객체에 접근해 CRUD 작업을 할 수 있다.

이 때 객체가 메모리에 할당되어 소프트웨어에 실체화 된 것을 instance라 한다. e.g. a = Drink.objects.get(id=1) 여기서 a.

QuerySet은 Metadata mapping이다. 이 안에 객체 등이 들어있는 형태다.

 

이 과정의 코드는 기본적으로 <모델 class명>.objects.<method> 형태를 사용하고, 이 뒤에도 dot notation을 통해 연쇄적으로 객체나 객체의 properties에 접근할 수 있다. 여기서 objects는 model class를 통해서 CRUD 작업을 제공하는 manager class이고, 이 뒤에 붙는 method는 DB에 쿼리 작업을 수행하는 manager class의 method이다.

출처 https://medium.com/@jairvercosa/manger-vs-query-sets-in-django-e9af7ed744e0

QuerySet API

API는 Application Programming Interface의 약자로, 응용 프로그램에서 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있도록 만든 인터페이스를 의미한다. QuerySet API는 QuerySet을 만들고 가공하는 데 사용할 수 있는 명령어라고 보면 될 것 같다.

 

cf. 웹서비스에서는 API의 의미가 확장되어 데이터를 요청, 제공하는 규격도 의미한다(참고 링크). 이전까진 이 의미가 더 친숙해서 데이터를 요청하고 받아올 수 있는 무언가, 라고만 어렴풋이 인식하고 있었다. 내가 API를 처음 접한 건 기상청이 제공하는 API를 사용해 날씨 데이터를 받아올 때라고 생각했지만 실은 프로그래밍 언어를 사용할 때부터 이미 쓰고 있던 거였다.

 

QuerySet API의 method들은 QuerySet을 반환하기도 하고 아닌 값을 반환하기도 한다.

QuerySet은 리스트 형태로, Slicing이 가능해 index를 써서 QuerySet 일부 요소에 접근할 수 있다.

QuerySet = list는 아니다. 객체들을 담은 리스트는 list(<QuerySet>)으로 만들어야 된다.

Create

Method

Return

Remarks

create(<column명>=<값>)

없음

객체를 만들고 저장

get_or_create(<column명>=<값>)

object와 boolean을 담은 Tuple

기존에 있어서 가져오면 (object, False),

새로 생성하면 (object, True)

update_or_create(<조건>, defaults={<column명 문자열>:<값>})

object와 boolean을 담은 Tuple

기존에 있어서 수정했으면 (object, False),

새로 생성하면 (object, True)

조건대로 찾아서 없으면 defaults dictionary의 값을 바탕으로 생성하기 때문에 여기엔 필수 column 정보를 다 입력해야 된다.

get으로 조회하기 때문에 반드시 결과가 하나인 <찾을 column명>=<찾을 값> 조건을 주어야 된다.

bulk_create(<넣을 object들을 요소로 갖는 list>)

없음

shell에서 실행한 결과로는 object의 id가 None으로 나온다. DB엔 잘 들어가 있다.

batch_size argument도 있다. batch_size는 한 쿼리당 몇개의 object를 넣을지 설정하는 역할. default는 None이라 주어진 걸 한 번에 다 넣는다.

위 표에 있는 method들은 save()까지 포함된 효과를 갖는다.

Retrieve

Method

Return

Remarks

all()

QuerySet

-

get(<결과가 한 개인 조건>)

object 한 개

0개 또는 2개 이상의 결과를 가지면 에러

filter(<조건>)

0개 이상의 결과를 담은 QuerySet

결과가 0개면 <QuerySet []>

exclude(<조건>)

0개 이상의 결과를 담은 QuerySet

조건을 여러개 주면 그 조건을 전부 만족하는 것만 빼고 나머지를 반환한다.

values()

Dictionary를 담은 QuerySet

-

values_list()

Tuple을 담은 QuerySet

-

count()

QuerySet 안에 들어있는 object의 개수

object를 담은 list에다 count()를 붙이니 count는 단 한 개의 argument를 갖게 되어 있다는 에러가 났다.

exists()

boolean

QuerySet에 값이 있으면 True, 없으면 False를 반환한다.

list, object 등에다 붙여 쓸 수 없다.

order_by(<조건>)

조건에 따라 정렬된 QuerySet

조건은 column명을 문자열로 1개 이상 갖는다. 그대로 쓰면 asc, -를 넣으면 desc이다.

e.g. 'id', '-id'

조건으로 query expression을 사용해 정렬할 수 있다.

아무 조건도 안 주면 아무 순서도 아닌듯.

first()

object 한 개

QuerySet의 첫번째 object를 반환한다.

없으면 None을 반환한다.

QuerySet이 정렬된 게 아니라면 pk 순으로 정렬한다.

last()

object 한 개

QuerySet의 마지막 object를 반환한다.

그 외는 first()와 같다.

aggregate(<aggregation function>)

aggregation function의 결과값을 value로 갖는 dictionary

e.g. aggregation function 중 하나인 Count(위에 있는 count()와 다름)를 써서 categories 테이블에 있는 row의 개수를 센다면,

Category.objects.aggregate(Count('menu'))로 할 수 있다.

key값은 function 안에 들어간 문자열과 function이름을 자동으로 조합해서 넣는다.

{'menu_count':15}

만일 key를 custom하고 싶다면 custom하고 싶은 key를,

Category.objects.aggregate(<custom_key>=Count('menu')) 이렇게 주면 된다.

order_by의 조건에 query expression을 넣어 유용하게 사용한 참고 링크

aggregation functions 참고 링크

Update

Method

Return

Remarks

update(<속성명>=<바꿀 값>)

수정한 row의 개수

여러 개의 객체가 든 QuerySet에다 update를 주면 한꺼번에 수정할 수 있다.

update를 쓰지 않을 때

이 이미지에서는 update를 사용하는 대신 instance를 수정했다

그러면 <instance>.save()를 치기 전에는 DB에 반영이 되지 않는다.

Delete

Method

Return

Remarks

Delete()

(<삭제한 개수>, {<object type>:<해당 type당 삭제한 개수>})

instance로 가져와서 delete()해도 삭제가 된다.

여러 개의 객체가 든 QuerySet에다 delete를 주면 한꺼번에 수정할 수 있다.


정참조

fk to pk 방향대로 나아가면서 조회하면 정참조. field로 연결되어 있으니 조회하기 편하다.

역참조

반대 방향을 조회하면 역참조. 장고에서 지원한다.

사용할 때 _set 뒤에 괄호 없음!!!!!!!!!!

역참조

실행 예시

더보기

모델 상태

class Menu(models.Model):
    name = models.CharField(max_length=5)

    class Meta:
        db_table = 'menus'


class Category(models.Model):
    name = models.CharField(max_length=10)
    menu = models.ForeignKey('Menu', on_delete=models.CASCADE)

    class Meta:
        db_table = 'categories'


class Drink(models.Model):
    name = models.CharField(max_length=20)
    category = models.ForeignKey('Category', on_delete=models.CASCADE)
    english_name = models.CharField(max_length=50)
    description = models.CharField(max_length=100, null=True)
    is_new = models.BooleanField()

    class Meta:
        db_table = 'drinks'

 

 

이 글을 쓰면서 이전에는 그저 함수 역할로만 인식하고 사용하던 method들과 장고 ORM, 객체에 대해서 좀 더 이해할 수 있었다

 

. 예전에 발생했던 manager과 instance 관련 에러 두가지에 대해서 잘 설명할 수 있을 만큼 이해하는 게 다음 목표다.

일단 메모

must be an instance 참고 링크

manager isn't accessible via instance 참고 링크