[Django] shell_plus에서의 CRUD

작성:    

업데이트:

카테고리:

태그: ,

CRUD

  • 대부분의 컴퓨터 소프트웨어가 가지는 기본적인 데이터 처리 기능
  • Create(생성), Read(읽기), Update(갱신), Delete(삭제)


Create

Create 1 : 인스턴스, 데이터 추가, 저장 따로

// article 인스턴스를 Article 클래스에서 제작
In [4]: article = Article()

// 아직 DB에는 반영되지 않은 것
In [9]: article
Out[9]: <Article: Article object (None)>

// instance에 데이터가 없는 것
In [10]: article.title
Out[10]: ''

// 데이터(property)를 추가
In [11]: article.title = 'first'

In [12]: article.content = 'test'

// 역시 아직도 DB에는 반영이 안 되었음
In [13]: article
Out[13]: <Article: Article object (None)>

// save() : 현재 설정된 값들이 DB에 반영!! ⭐
In [14]: article.save()

// DB에 반영이 되었다. 그냥 인스턴스를 shell에 입력하면 PK(id)가 함께 나옴
In [15]: article
Out[15]: <Article: Article object (1)>

위의 과정으로 인스턴스를 생성, 정의, 저장하여 DB에 반영까지 할 수 있다.


image

DB에 하나의 record가 table에 저장되었음을 확인


Create 2 : 인스턴스 생성할 때 데이터 함께 생성, 저장은 따로

In [1]: article = Article(title='second', content='django!!')

In [2]: article.save()

instance를 정의할 때 class 내에 property를 함께 정의


image

DB에 잘 반영되었다.


Create 3 : 인스턴스 생성, 데이터, 저장 한 번에

In [3]: Article.objects.create(title='third', content='django~~')
Out[3]: <Article: Article object (3)>

QuerySet API - create()를 사용


image

역시 DB에 잘 반영되었다.


save() method

  • 객체를 DB에 저장
  • 데이터 생성 시 save()를 호출하기 전에는 객체의 ID값을 알 수 없다.
  • ID 값은 django가 아니라 DB에서 계산되기 때문
  • 단순히 model을 instance화하는 것은 DB에 영향을 미치지 않기 때문에 반드시 save() 필요


__str__(self) method

__str__(self) 정의 전

In [1]: article = Article.objects.create(title='str test', content='str test~~')

In [2]: article
Out[2]: <Article: Article object (19)>

pk인 id가 object의 고유 번호를 함께 출력할 뿐, 무슨 정보인지 알 수가 없다.


__str__(self) 정의

# models.py

class Article(models.Model):
    title = models.CharField(max_length=10)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    def __str__(self):
        return self.title
  • 표준 파이썬 클래스의 메소드인 str()을 정의
  • 각각의 object가 사람이 읽을 수 있는 문자열을 return하도록 할 수 있다.
  • 작성/저장 후 반드시 shell_plus를 재시작해야 반영


__str__(self) 정의 후

In [1]: article = Article.objects.create(title='str test', content='str test~~')

In [2]: article
Out[2]: <Article: str test>

title로 instance가 표시되어 어떤 record인지 판별이 쉬워졌다.


QuerySet과 List

  • article을 Article의 objects 모두로 지정하면 list 형식으로 저장
  • indexing, slicing, for문 등 list 자료형의 조작이 모두 가능
In [1]: Article.objects.all()
Out[1]: <QuerySet [<Article: first>, <Article: second>, <Article: third>]>

In [2]: article = Article.objects.all()

In [3]: article[0]
Out[3]: <Article: first>

In [4]: article[1:]
Out[4]: <QuerySet [<Article: second>, <Article: third>]>

In [5]: type(article)
Out[5]: django.db.models.query.QuerySet

In [6]: for a in article:
   ...:     print(a.title)
   ...: 
first
second
third


READ

all()

  • 현재 QuerySet의 복사본을 반환
  • QuerySet : 모든 인스턴스의 집합
In [7]: Article.objects.all()
Out[7]: <QuerySet [<Article: first>, <Article: second>, <Article: third>]>


get()

  • ClassName.Manager.get(lookup_key=lookup_value) 형식
  • 주어진 lookup 매개변수와 일치하는 객체 변환
  • 위와 같은 특징 때문에 PK와 같이 고유성(unique)을 보장하는 조회에서 사용

  • lookup 매개변수는 2개 이상 사용 가능

image

content가 django!!로 중복된 상황을 만들기 위해 위와 같이 DB를 바꿔 등록해보았다.

In [1]: Article.objects.get(content='django!!', title='second')
Out[1]: <Article: second>


오류 발생 예시

  • DoesNotExist 예외 : 객체를 찾을 수 없을 때
  • MultipleObjectReturned 예외 : 둘 이상의 객체를 찾았을 때
// 가져오는 key가 없는 경우
In [1]: article = Article.objects.get(pk=100)
DoesNotExist: Article matching query does not exist.

// 가져오는 lookup 조건에 해당하는 object가 2개 이상인 경우
In [2]: Article.objects.get(content='django!!')
MultipleObjectsReturned: get() returned more than one Article -- it returned 2!


filter()

  • 주어진 lookup 매개변수와 일치하는 객체를 포함하는 새 QuerySet 반환

  • all() querySet API처럼 python에서 list로 처리 가능

중요⭐ get()은 객체 하나만 조회하며 객체 자체를 반환, filter()는 여러 개의 객체를 리스트로 반환하며, 한 개를 반환하더라도 리스트에 담아 반환

In [3]: Article.objects.filter(content="django!!")
Out[3]: <QuerySet [<Article: second>, <Article: third>]>

In [4]: Article.objects.filter(title='first')
Out[4]: <QuerySet [<Article: first>]>


Update

# Article의 object 중 pk가 5인 object를 찾아 article에 저장
In [6]: article = Article.objects.get(pk=5)

# article의 title 검색
In [7]: article.title
Out[7]: 'first'

# article의 title을 'byebye'로 갱신
In [8]: article.title = 'byebye'

# article을 DB에 저장/반영
In [9]: article.save()

# article의 title 갱신 확인
In [10]: article.title
Out[10]: 'byebye'

image

  • id(pk)가 5인 record의 title이 ‘first’에서 ‘byebye’로 갱신
  • updated_at도 수정 일시로 갱신


Delete : delete()

  • QuerySet의 모든 행에 대해 SQL 삭제 쿼리를 수행
  • 삭제된 객체 수와 객체 유형당 삭제 수가 포함된 딕셔너리 반환
# pk가 5인 record를 article에 저장
In [11]: article = Article.objects.get(pk=5)

# article을 제거하면 mapping된 record도 제거
In [12]: article.delete()
Out[12]: (1, {'articles.Article': 1})

# pk가 5인 record 조회, DoesNotExist 에러 발생
In [13]: Article.objects.get(pk=5)
DoesNotExist: Article matching query does not exist.

image

  • pk가 5인 record가 실제로 제거됨을 확인 가능


Field lookups

  • 조회 시 특정 조건을 지정
  • QuerySet 메서드 filter(), exclude() 미치 get()에 대한 키워드 인수로 지정
  • underbar 2개로 작성(‘__’)
  • 사용 예시
    • Article.objects.filter(pk__gt=6) : pk가 6 이상인 record
    • Article.objects.filter(content__contains=’ja’) : content가 ‘ja’를 포함하는 record
In [15]: Article.objects.filter(pk__gt=6)
Out[15]: <QuerySet [<Article: third>]>

In [16]: Article.objects.filter(content__contains='ja')
Out[16]: <QuerySet [<Article: second>, <Article: third>]>


QuerySet API

댓글남기기