Django | 의식의 흐름대로 하는QuerySet API 연습

김민호·2021년 11월 11일
0

DJANGO

목록 보기
17/18

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

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="chldmsghks@gmail.com")

In [10]: author1
Out[10]: <Author: Author object (4)>

In [11]: author1.name
Out[11]: '최은환'

In [12]: author1.email
Out[12]: 'chldmsghks@gmail.com'

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
profile
개발자로서의 삶은 https://velog.io/@maxminos 에서 기록하고 있습니다 😀

0개의 댓글