Django | 의식의 흐름대로 하는QuerySet API 연습
ORM이란?
ORM(Object Relational Mapping)
: 객체 관계 맵핑OOP(Object Oriented Programming)
: 객체 지향 프로그래밍RDB(Relational Database)
: 관계형 데이터베이스- 쉽게 말해서 ORM이란 데이터베이스 문법인 SQL문을 작성할 필요 없이 클래스의 메서드를 통해 간접적으로 데이터베이스를 조작할 수 있게 하는 방법
- 그렇기 때문에 Django ORM 과 SQL의 관계를 잘 이해하고 있어야 한다. 관련 포스팅은 작성중!
초기세팅
- 장고 초기세팅 완료 후
queryset
이라는 프로젝트 파일 생성 blogs
라는 앱 생성- 장고 공식 문서의 데이터 모델로
models.py
작성
from django.db import models
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
class Meta:
db_table = "blogs"
class Author(models.Model):
name = models.CharField(max_length=200)
email = models.EmailField()
class Meta:
db_table = "authors"
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
headline = models.CharField(max_length=255)
body_text = models.TextField()
pub_date = models.DateField()
mod_date = models.DateField()
authors = models.ManyToManyField(Author)
number_of_comments = models.IntegerField()
number_of_pingbacks = models.IntegerField()
rating = models.IntegerField()
class Meta:
db_table = "entries"
-
DB와 연동 후 ORM 연습을 하기 위한 임의의 데이터 삽입
-
ManyToMany
테이블 : entries 테이블과 authors 테이블은 다대다 관계로 연결되어 있다. 그렇기 때문에 DB에 자동으로entries_authors
라는 중간 테이블이 생겼다. 이ManyToMany
테이블 기능은 장고에만 있는 기능이라고 한다.Q.
다대다 관계의 테이블은 ORM 어떻게 쓰는지 확인
Q.
다대다 관계인데authors = models.ManyToManyField(Author)
이 컬럼이 entries 테이블이 있는 상황이다. 만약에 authors 테이블에entries = models.ManyToManyField(Entry)
컬럼을 생성하면 어떻게 될까?
Q.
Column(컬럼), row(로우), field(필드) 란?
Q.
쿼리셋을 반환하는 메소드와 그렇지 않은 메소드
- QuerySet 반환하는 :
all
,filter
,exclude
,values
,values_list
,
추가 공부할 메소드 :annotate
,order_by
,select_related
,prefetch_related
- QuerySet 반환하지 않는(=인스턴스를 반환) :
create
,get
,update
,delete
,save
,exists
추가 공부할 메소드 :get_or_create
,update_or_create
,bulk_create
,bultk_update
,count
,first
,aggregate
QuerySet Method
QuerySet를 반환하는 메소드
1. all()
- 한 테이블의 모든 레코드를 가져오며 그 결과로 쿼리셋을 반환하고 그 쿼리셋 안에는 각각 인스턴스가 들어있다.
In [17]: Author.objects.all()
Out[17]: <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>, <Author: Author object (3)>, <Author: Author object (4)>]>
- 보통
all()
과 같이 쿼리셋을 반환하는 메소드들은 for
문과 함께 쓰이면서 쿼리셋 안의 인스턴스 하나하나에 접근하여 사용된다
In [22]: for author in Author.objects.all():
...: print(author.id)
...:
1
2
3
4
In [23]: for author in Author.objects.all():
...: print(author.name)
...:
김민호
taehoon
지광선
최은환
In [24]: for author in Author.objects.all():
...: print(author.email)
...:
minho@gmail.com
taehoon@gmail.com
wlrhkdtjs@gmail.com
chldmsghks@gmail.com
2. filter() & exclude()
- 가장 자주 사용하는 메소드로서 한 테이블의 특정 레코드를 가져오기 위해 사용한다
filter(**kwargs)
: 키워드 인자로 주어진 lookup 조건에 일치하는 레코드들의 QuerySet을 반환한다.
In [29]: Blog.objects.filter(tagline="태그1")
Out[29]: <QuerySet [<Blog: Blog object (1)>, <Blog: Blog object (4)>, <Blog: Blog object (5)>]>
In [30]: Blog.objects.filter(tagline="태그1").filter(id=4)
Out[30]: <QuerySet [<Blog: Blog object (4)>]>
In [31]: Blog.objects.filter(tagline="태그1").filter(id=2)
Out[31]: <QuerySet []>
In [32]: Blog.objects.filter(tagline="태그1").exclude(id=4)
Out[32]: <QuerySet [<Blog: Blog object (1)>, <Blog: Blog object (5)>]>
3. values()
- iterable로 사용될 때 모델 인스턴스가 아닌 dictionary을 포함하는 QuerySet을 반환
In [34]: Blog.objects.all().values()
Out[34]: <QuerySet [
{'id': 1, 'name': '김민호블로그', 'tagline': '태그1'},
{'id': 2, 'name': '김민호블로그2', 'tagline': '태그22'},
{'id': 3, 'name': '김민호블로그3', 'tagline': '태그33'},
{'id': 4, 'name': '김태훈블로그', 'tagline': '태그1'},
{'id': 5, 'name': '', 'tagline': '태그1'}
]>
- 반환된 쿼리셋은 딕셔너리 형태이기 때문에 value 값을 불러오고자 할 때는
bracket notation
으로 불러와야 한다
In [49]: blogs = Blog.objects.filter(tagline="태그1").values()
In [50]: blogs
Out[50]: <QuerySet [
{'id': 1, 'name': '김민호블로그', 'tagline': '태그1'},
{'id': 4, 'name': '김태훈블로그', 'tagline': '태그1'},
{'id': 5, 'name': '', 'tagline': '태그1'}
]>
In [51]: for blog in blogs:
...: print(blog["id"])
...:
1
4
5
In [17]: Author.objects.all()
Out[17]: <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>, <Author: Author object (3)>, <Author: Author object (4)>]>
all()
과 같이 쿼리셋을 반환하는 메소드들은 for
문과 함께 쓰이면서 쿼리셋 안의 인스턴스 하나하나에 접근하여 사용된다In [22]: for author in Author.objects.all():
...: print(author.id)
...:
1
2
3
4
In [23]: for author in Author.objects.all():
...: print(author.name)
...:
김민호
taehoon
지광선
최은환
In [24]: for author in Author.objects.all():
...: print(author.email)
...:
minho@gmail.com
taehoon@gmail.com
wlrhkdtjs@gmail.com
chldmsghks@gmail.com
filter(**kwargs)
: 키워드 인자로 주어진 lookup 조건에 일치하는 레코드들의 QuerySet을 반환한다.In [29]: Blog.objects.filter(tagline="태그1")
Out[29]: <QuerySet [<Blog: Blog object (1)>, <Blog: Blog object (4)>, <Blog: Blog object (5)>]>
In [30]: Blog.objects.filter(tagline="태그1").filter(id=4)
Out[30]: <QuerySet [<Blog: Blog object (4)>]>
In [31]: Blog.objects.filter(tagline="태그1").filter(id=2)
Out[31]: <QuerySet []>
In [32]: Blog.objects.filter(tagline="태그1").exclude(id=4)
Out[32]: <QuerySet [<Blog: Blog object (1)>, <Blog: Blog object (5)>]>
In [34]: Blog.objects.all().values()
Out[34]: <QuerySet [
{'id': 1, 'name': '김민호블로그', 'tagline': '태그1'},
{'id': 2, 'name': '김민호블로그2', 'tagline': '태그22'},
{'id': 3, 'name': '김민호블로그3', 'tagline': '태그33'},
{'id': 4, 'name': '김태훈블로그', 'tagline': '태그1'},
{'id': 5, 'name': '', 'tagline': '태그1'}
]>
bracket notation
으로 불러와야 한다In [49]: blogs = Blog.objects.filter(tagline="태그1").values()
In [50]: blogs
Out[50]: <QuerySet [
{'id': 1, 'name': '김민호블로그', 'tagline': '태그1'},
{'id': 4, 'name': '김태훈블로그', 'tagline': '태그1'},
{'id': 5, 'name': '', 'tagline': '태그1'}
]>
In [51]: for blog in blogs:
...: print(blog["id"])
...:
1
4
5
dot notation
으로 접근하면 AtrributeError
발생
In [52]: for blog in blogs:
...: print(blog.id)
...:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-52-b3c04ad11c93> in <module>
1 for blog in blogs:
----> 2 print(blog.id)
3
AttributeError: 'dict' object has no attribute 'id'
4. values_list()
values()
가딕셔너리
를 반환한다면,values_list()
는튜플
을 반환한다
In [53]: Blog.objects.all().values_list()
Out[53]: <QuerySet [
(1, '김민호블로그', '태그1'),
(2, '김민호블로그2', '태그22'),
(3, '김민호블로그3', '태그33'),
(4, '김태훈블로그', '태그1'),
(5, '', '태그1')
]>
- 각 튜플에는 values_list () 호출에 전달 된 각 필드 또는 표현식의 값이 포함되어 있으므로 첫 번째 항목이 첫 번째 필드
QuerySet 반환하지 않는 메소드
1. create()
- create()는 쿼리셋을 반환하지 않고 해당 인스턴스 1개를 반환하기 때문에 바로 속성에 접근해서 사용할 수 있다
In [9]: author1 = Author.objects.create(name="최은환", email="[email protected]")
In [10]: author1
Out[10]: <Author: Author object (4)>
In [11]: author1.name
Out[11]: '최은환'
In [12]: author1.email
Out[12]: '[email protected]'
2. get()
- 지정된 조회 매개변수와 일치하는 인스턴스를 반환한다. 이 매개 변수는 필드 조회에 설명된 형식이어야 한다.
In [13]: Author.objects.get(id=2)
Out[13]: <Author: Author object (2)>
In [14]: print(Author.objects.get(id=2))
Author object (2)
In [15]: a = Author.objects.get(id=2)
In [16]: print(a)
Author object (2)
3. update()
- 지정된 필드에 대해 업데이트 쿼리를 수행하고 일치하는
행 수
를 반환한다
In [59]: Blog.objects.filter(id=3).update(tagline="홀수 태그")
Out[59]: 1 # 총 업데이트된 row 개수
4. delete()
- QuerySet의 모든 행에 대해 SQL 삭제 쿼리를 수행하고
삭제 된 개체 수
와개체 유형별 삭제 횟수가 있는 dictionary
를 반환한다
In [60]: Blog.objects.filter(id=5).delete()
Out[60]: (1, {'blogs.Blog': 1})
5. save()
INSERT
또는UPDATE
를 수행하는 method로, 단일 객체에 대해서 업데이트를 수행할 때 많이 사용- blogs 테이블에서 id=4의 name을 수정하고 싶을 경우를 예로 들어보자
id=4인 인스턴스를 변수 blog에 담고 그 인스턴스의 name 필드를 불러오면 아래와 같다.
In [73]: blog = Blog.objects.get(id=4)
In [74]: blog.name
Out[74]: '김태훈의 블로그'
여기서 '김태훈의 블로그'라는 이름을 수정하고 싶을 경우
In [75]: blog.name = "김태훈의 새로운 블로그!!!!!"
이라고 blog.name
을 새롭게 선언해준다. 이제 쉘에서 blog.name
를 치면 "김태훈의 새로운 블로그!!!!!" 이게 나오지만 현재 데이터베이스에는 저장이 되지 않은 상황이다. "김태훈의 새로운 블로그!!!!!"를 DB에 저장하고 싶을 경우에 save()
메소드를 쓴다
In [76]: blog.save()
In [77]: blog.name
Out[77]: '김태훈의 새로운 블로그!!!!!'
6. exists()
- filter()와 함께 서용해서 filter 조건에 맞는 데이터가 있는지 조회, 존재하면 True 존재하지 않으면 False를 반환한다.
In [78]: Blog.objects.filter(id=3).exists()
Out[78]: True
In [79]: Blog.objects.filter(tagline="태그태그").exists()
Out[79]: False
Author And Source
이 문제에 관하여(Django | 의식의 흐름대로 하는QuerySet API 연습), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@maxkmh/Django-의식의-흐름대로-하는QuerySet-API-연습저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)