#참고문서

https://docs.djangoproject.com/ko/2.2/topics/db/models/

[TOC]

1.Crud

1.SQL 기본단어 정리

명령어 : pip freeze > requirements.txt 현재 설정 환경 저장.\

1.기본틀

  1. 테이블(table)
  2. PK : Primary Key(기본키)
  3. 열(Column),
  4. 행(row), 레코드

2.SQL

C: create

R: read

U: update

D: delete

2. ORM 객체 언어

  • 번역기의 개념
  • 장점
    • 개발의 생산성이 높아 졌다.
    • SQL을 몰라도 사용 가능하다.
    • SQL 의 절차적인 접근이 아닌 객체 지향적 접근이 가능하다.
    • 매핑정보가 명확하여 ERD를 보는 것에 대한 의존도를 낮출 수 있다.
    • ORM은 독립적으로 작성되어 있고, 해당 객체들을 대활용 할 수 있다. 개발자는 객체에 집중함으로써 해당 DB에 종속될 필요 없이 자유롭게 개발할 수 있다.
  • 단점
    • ORM 만으로 완전히 거대한 서비스를 구현하기가 어렵다.
      • 사용하기는 편하지만, 설계는 매우 신중하게 해야함.
      • 프로젝트의 규모가 커질 경우 난이도가 올라가게 된다.
      • 순수 SQL보다 약간의 속도 저하가 생길 수 있다.
    • 이미 프로세스가 많은 시스템에서는 ORM으로 대체하기가 어렵다.
  • 결론
    • 생산성!
    • ORM을 사용하여 얻게 되는 생산성은 약간의 성능저하나 다른 단점들을 상쇄할 만큼 뛰어나기 때문.
    • 장점으로 인한 생산성 증가가 훨씬 비중이 크기 때문에 현대에는 대부분의 프레임워크들이 ORM을 사용하고 있다.
    • 즉, 우리는 DB를 객체(objec) - 인스턴스(instance)로 조작하기 위해서 ORM을 배운다.

1. 모델

  1. 개념

    • 모델은 단일한 데이터에 대한 정보를 가지고 있다.
    • 필수적인 필드(컬럼, 열)와 데이터(레코드, 행)에 대한 정보를 포함한다. 일반적으로 각각의 모델(클래스)는 단일한 데이터베이스 테이블과 매핑(연결, 연동)된다.
    • 모델은 부가적인 메타데이터를 가진 DB의 구조(layout)를 의미
    • 사용자가 저장하는 데이터들의 필수적인 필드와 동작(behavior)을 의미
  2. Field

    • CharField()

      • 길이의 제한이 있는 문자열을 넣을 때 사용

      • max-length는 필수 인자다.

      • 필드의 최대 길이(문자)이며, DB와 django의 유효성검사(값을 검증)에서 사용됨.

      • 텍스트 양이 많을 경우 TextField()로 사용


    • TextField()

      • 글자 수가 많을 때 사용

      • max_length 옵션을 줄 수 있지만 모델과 실제 DB에는 적용되지 않는다. 길이 제한을 주고 싶다면 CharField()를 사용해야 한다.


    • DateTimeField()

      • 시간과 날짜를 기록하기 위한 필드
      • auto_now_add=True
        • django ORM이 최초 INSERT(테이블에 데이터 입력)시에만 현재 날짜와 시간 작성
        • 최초 생성 일자
      • auto_now=True
        • django ORM이 SAVE를 할 때마다 현재 날짜와 시간 작성
        • 최종 수정 일자

    $ djaongo model field 공식문서 확인!! field에 대한 모든 것들을 볼 수 있다.

  3. model 로직

    • DB 컬럼과 어떠한 타입으로 정의할 것인지에 대해 django.db 모듈의 models의 상속을 받아서 적용된다.
    • 각 모델은 django.db.models.Model 클래스의 서브 크래스로 표현된다.(자식클래스)
    • 모든 필드는 기본적으로 NOT NULL 조건이 붙는다.(NULL 값이 들어갈 수 없다.)
    • 각각의 클래스 변수들은 모델의 데이터 베이스 필드를 나타낸다.
  4. Migrations

    • migrations

      • $ python mange.py makemigrations

      • makemigrations 명령어는 모델(model.py)을 작성/변경한 사항을 django에게 알리는 작업.(ORM에 보낼 Python 코드 설계도를 작성)

      • 테이블에 대한 설계도를 생성.

    • migrate

      • migrations 로 만든 설계도를 기반으로 실제 DB 테이블을 만듦. => db.sqlite3 파일에 DB를 반영한다.
      • 모델에서의 변경사항들과 DB 스키마가 동기화를 이룬다.
      • 명령어 : python manage.py makemigrations : migrate 생성, models.py 변경시 업데이트도 해줘야 함
      • 명령어 : python manage.py sqlmigrate articles 0001 : ORM 해석본 생성
    • SQLite extentions 설치 와 테이블 확인 방법

      • `ctrl + shift + p > Sqlite: Open database >
    • 추가사항

      • $ python manage.py sqlmigrate app_name 0001
        
      • 해당 migrations 설계도가 SQL 문으로 어떻게 해석 되어서 동작 할지 미리 볼 수 있다.

      • $ python mange.py showmigrations
        
      • migraions 설계도들이 migrate 됐는지 안됐는지 확인


    • :traffic_light: Model 변경 시 작성 순서

      1. models.py : 작성 및 변경(생성/수정)

      2. makemigrations: migrations 파일 만들기(설계도)

      3. migrate: 실제 DB에 적용 및 동기화(테이블 생성)


        테이블의 이름은 app이름과 model 에 작성한 class 이름이 조합되어져서 자동으로 만들어진다.(모두 소문자)

        모델의 클래스변수들은 반드시 소문자로 써야 한다.

        db.sqlite3는 (데이터베이스) 서버에 올라가지 않는다.

:mount_fuji: 2. sqlite3 설치 및 확인 명령어

  • windows- 환경설정 :mount_fuji:

    sqlite3 홈페이지 > download > Precompiled Binaries for Windows > sqlite-dll-win64-x64-3290000.zip + sqlite-tools-win32-x86-3290000.zip 다운로드 후 > C드라이브에 sqlite3에 5개의 파일을 넣어 준다.

    환경변수 창에서 아래 테이블에 C:\sqlite 환경변수 추가

  • code ~/.bashrc > alias sqlite3=”winpty sqlite3” 추가 > source ~/.bashrc 로 적용 > sqlite3 db.sqlite3로 열기

3. CRUD (DB API 조작)

  1. Django Shell

    • django 프로젝트 설정이 로딩된 파이썬 shell
    • 일반 파이썬 shell 로는 django 환경에 접근 불가
    • 즉, django 프로젝트 환경에서 파이썬 shell을 활용한다고 생각하자.
      • pip install ipython 보기좋게 해준다.
    • python manage.py shell 명령어로 켜준다.
    • 테이블 내용을 전부 조회(READ) : DB에 쿼리를 날려서 인스턴스 객체 전부를 달라고 하는 뜻
      • 만약에 케로드가 하나라면, 인스턴스 단일 객체로 반환.
      • 두개 이상이면, QuerySet 형태로 변환
    • ORM 문법 == sql 문법
    • Article.objects.all() == SELECT*FROM articles_article;

4. CREATE

1. QuerySet 기본 개념

- 전달 받은 객체의 목록

  - QuerySet : 쿼리 set 객체
  - Query: 단일 객체

- DB로부터 데이터를 읽고, 필터를 걸거나 정렬 등을 수행

- Query를 던지는 Language(django ORM)를 활용해서 DB에게 데이터에 대한 조작을 요구한다.

  <hr>

`QuerySet`

- objects 사용하여 다수의 데이터를 가져오는 함수를 사용할 때 반환되는 객체
- 단일한 객체를 반환(리턴)할 때는 테이블(class)의 인스턴스로 리턴됨

`objects`

- Model Manager와 Django Model 사이의 Query 연산의 인터페이스 역할을 해주는 친구
- 즉, `models.py`에 설정한 클래스(텡블)을 불러와서 사용 할때 DB와의 인터페이스 역할(쿼리를 날려주는 역할)을 하는 매니저이다.
- 쉽게 이해하려면 ORM의 역할이라고 생각하면 된다.
- DB -----------objects------------Python Class(models.py)

  1. 데이터 객체를 만드는 (생성, CRETE)하는 3가지 방법

  2. shell : 일반적인 로직

    $ python mange.py shell
    #SQL - 특정 테이블에 새로운 레코드(행)을 추가하여 데이터 추가
    # INSERT INTO table (column1, column2, ...) VALUES (value1, value2, ...)
    # INSERT INTO articles_article(title, content) VALUES ('first', 'django!')
       
    >>> article = Article() #Articl class 로부터 article 인스턴스 생성
    >>> article.title = 'first' # 인스턴스 변수(title)에 값을 할당
    >>> article.content = 'django!' #인스턴스 변수(content)에 값을 할당
    # save를 하지 않으면 아직 DB에 값이 저장되지 않음
    >>> article
    <Article: Article object (None)>
    >>> Articl.objects.all()
    <QuerySet []>
       
    # save를 하고 확인해 보면 저장도니 것을 확인 할 수 있다.
    >>> article.save()
    >>> article
    <Article: Article object (1)>
    >>> Article.objects.all()
    <QuerySet [<Article: Article object (1)>]>
       
    # 인스턴스 article 을 활용하여 변수에 접근할 수 있다(저장된 값 확인)
    >>> article.title
    'first'
    >>> article.content
    'django!'
    >>> article.created_at
    datetime.datetime(2019, 8, 21, 2, 43, 56, 141231, tzinfo=<UTC>)
           
    
  3. 두번째 방식

    >>> article = Article(title='second', content='django!!')
    >>> article.save()
    
  4. 세번째 방식

  • create()를 사용하면 쿼리셋 객체를 생성하고 저장하는 로직이 한번의 스텝으로 끝난다.
   >>> Article.objects.create(title='third', content='django!!!')
   In [21]: test = Article.objects.all()
   
   In [22]: test
   Out[22]: <QuerySet [<Article: Article object (1)>, <Article: Article object (2)>, <Article: Article object (3)>]>
In [23]: article = Article()

In [24]: article.title = 'forth'

In [25]: article.content = 'django!!!!'

In [26]: article.save()
   
In [28]: article.id
Out[28]: 4

In [29]: article.pk
Out[29]: 4
  1. 유효성 검사
    • save 전에 full_clean() 메서드를 통해 article 이라는 인스턴스 객체가 검증(validation)에 적합한지를 알아 볼수 있다.
    • models.py에 필드 속성과 옵션에 따라 검증을 진행한다.(기본값: blank=False, null=False)
In [30]: article = Article()

In [31]: article.title = 'life is short, you need python'

In [32]: article.full_clean() #유효성 검증
---------------------------------------------------------------------------
ValidationError                           Traceback (most recent call last)
<ipython-input-32-ae01d73cadbe> in <module>
----> 1 article.full_clean()

~\Desktop\TIL2\04_django\01_django_orm_crud\venv\lib\site-packages\django\db\models\base.py in full_clean(self, exclude, validate_unique)
   1201
   1202         if errors:
-> 1203             raise ValidationError(errors)
   1204
   1205     def clean_fields(self, exclude=None):

ValidationError: {'title': ['이 값이 최대 10 개의 글자인지 확인하세요(입력값 30
자).'], 'content': ['이 필드는 빈 칸으로 둘 수 없습니다.']}

5. READ

  • models.py 수정이 되면 shell에 적용하기 위해서는 종료 후 python manage.py shell로 다시 키자.
In [1]: from articles.models import Article

In [2]: Article.objects.all()
Out[2]: <QuerySet [<Article: 1번글 - first : django!>, <Article: 2번글 - second : django!!>, <Article: 3
번글 - third : django!!!>, <Article: 4번글 - forth : django!!!!>]>

In [3]: Article.objects.create(title='fifth', content='django!!!!!')
   ...: Article.objects.create(title='fifth', content='django!!!!!')
Out[3]: <Article: 6번글 - fifth : django!!!!!>

In [4]: articles = Article.objects.filter(title='first')

In [5]: articles
Out[5]: <QuerySet [<Article: 1번글 - first : django!>]>

In [6]: type(articles)
Out[6]: django.db.models.query.QuerySet

모델 삭제 방법

  1. 0001 ~~ 번호 붙은 py 다 날리기
  2. db.splite3 날리기
  3. 처음부터 다시 하기

# 1. SELECT * FROM articles_article;
# 1. DB에 있는 모든 글 가져오기
>>> Article.objects.all()
----
# 2. SELECT * FROM articles_article WHERE title='first';
# 2. DB에 저장된 글 중에서 title이 first인 글만 가져오기
>>> Article.objects.filter(title='first')
----
# 3. SELECT * FROM articles_article WHERE title='first' LIMIT 1;
# 3. DB에 저장된 글 중에서 title이 first인 글 중에서 첫번째 글만 가져오기
>>> Article.objects.all().first()
>>> Article.objects.all().last() #마지막 값
----
# 4-1. SELECT * FROM articles_article WHERE id=1;
# 4-1. DB에 저장된 글 중에서 PK 가 1인 글만 가져오기
>>> Article.objects.get(pk=1)
 # PK 만 .get()으로 가져올 수 있다. (.get()은 값이 중복이거나 일치하는 값이 없으면 에러를 발생시킨다.) 즉, pk에만 사용하자.
    
# 4-2. filter의 경우 존재하지 안흥면 에러가 아닌 빈 쿼리셋을 반환한다. 마치 딕셔너리에서 value를 꺼낼 때 [] 방식으로 꺼내냐 혹은 .get의 방법으로 꺼내냐 하는 차이와 유사하다.
>>> Article.objects.filter(pk=100)
<QuerySet []>

#4-3. filter/get
# filter 자ㅔ가 여러 값을 가져올 수 있기 때문에 django가 개수를 보장하지 못한다. 그래서 0개, 1개라도 무조건 쿼리셋으로 반환한다.
----

# 5-1. 오름차순 (기본값)
# SELECT * FROM articles_article ORDER BY title ASC;
>>> Article.objects.order_by('pk') #원하는 값을 설정하면 됨. ex) title, content
# 5-2. 내림차순
# SELECT * FROM articles_article ORDER BY title DESC;
>>> Article.objects.order_by('-pk')

----

# 6. 쿼리셋은 리스트 자료형은 아니지만, 리스트에서 할 수 있는 인덱스 접근 및 슬라이싱이 모두 가능하다.
>>> Article.objects.all()[2]
>>> Article.objects.all()[1:3]

----
# 7. LIKE / startswith / endswith
# django ORM 은 이름(title)과 필터(contains)를 더블언더스코어(__)로 구분한다.

# LIKE
>>> Article.objects.filter(title__contains='fir')
 # fir을 포함하는 모든 것들
    
# startswith
>>> Article.objects.filter(title__startswith='fir')
 # fir로 시작하는 모든 것
# endswith
>>> Article.objects.filter(title__endswith='!')
# !로 끝나는 모든 것

get(id) 로 자료 불러오기

In [12]: article = Article.objects.get(pk=1)

In [13]: article
Out[13]: <Article: 1번글 - first : django!>

In [14]: type(article)
Out[14]: articles.models.Article

get 오류

  1. 빈 값
In [15]: Article.objects.get(pk=10)
---------------------------------------------------------------------------
DoesNotExist                              Traceback (most recent call last)
<ipython-input-15-0dfc467affe8> in <module>
----> 1 Article.objects.get(pk=10)

~\Desktop\TIL2\04_django\01_django_orm_crud\venv\lib\site-packages\django\db\models\manager.py in manager_method(self, *args, **kwargs)
     80         def create_method(name, method):
     81             def manager_method(self, *args, **kwargs):
---> 82                 return getattr(self.get_queryset(), name)(*args, **kwargs)
     83             manager_method.__name__ = method.__name__
     84             manager_method.__doc__ = method.__doc__

~\Desktop\TIL2\04_django\01_django_orm_crud\venv\lib\site-packages\django\db\models\query.py in get(self, *args, **kwargs)
    406             raise self.model.DoesNotExist(
    407                 "%s matching query does not exist." %
--> 408                 self.model._meta.object_name
    409             )
    410         raise self.model.MultipleObjectsReturned(

DoesNotExist: Article matching query does not exist.
  1. 중복값
In [17]: Article.objects.get(title='first')
---------------------------------------------------------------------------
MultipleObjectsReturned                   Traceback (most recent call last)
<ipython-input-17-d1fbb51d7cde> in <module>
----> 1 Article.objects.get(title='first')

~\Desktop\TIL2\04_django\01_django_orm_crud\venv\lib\site-packages\django\db\models\manager.py in manager_method(self, *args, **kwargs)
     80         def create_method(name, method):
     81             def manager_method(self, *args, **kwargs):
---> 82                 return getattr(self.get_queryset(), name)(*args, **kwargs)
     83             manager_method.__name__ = method.__name__
     84             manager_method.__doc__ = method.__doc__

~\Desktop\TIL2\04_django\01_django_orm_crud\venv\lib\site-packages\django\db\models\query.py in get(self, *args, **kwargs)
    410         raise self.model.MultipleObjectsReturned(
    411             "get() returned more than one %s -- it returned %s!" %
--> 412             (self.model._meta.object_name, num)
    413         )
    414

MultipleObjectsReturned: get() returned more than one Article -- it returned 2!

filter와 get의 차이

In [18]: Article.objects.filter(pk=10)
Out[18]: <QuerySet []>

6. UPDATE

수정

#article 인스턴스 객체의 인스턴스 변수에 들어있는 기존 값을 변경하고 저장
>>> article = Article.objects.get(pk=1)
>>> article.title = 'byebye'
>>> article.saver()
In [37]: article = Article.objects.get(pk=1)

In [38]: article
Out[38]: <Article: 1번글 - first : django!>

In [39]: article.title = 'byebye'

In [40]: article
Out[40]: <Article: 1번글 - byebye : django!>

In [41]: article.save()

In [42]: article.title
Out[42]: 'byebye'

7.DELETE

삭제

# article 인스턴스 객체를 생성 후 .delete() 매서드를 호출
>>> article = Article.objects.get(pk=1)
>>> article.delete()
	# 지워진 id 값은 따로 추가를 하지 않는다. (오류가 있어서 지웠다고 생각하기 떄문!)
  • 핵심은 우리는 ORM 을 통해 클래스의 인스턴스 객체로 DB를 조작할 수 있다는 것!
  • 앞으로 CRUD 로직을 직접 자성하면서 위에서 배운 코드들을 다시 활용할 것. (views.py)

3. ADMIN

#참고 사이트

https://docs.djangoproject.com/ko/2.2/ref/contrib/admin/

  • 사용자가 아닌 서버의 관리자가 활용하기 위한 페이지

  • models.py에 작성한 클래스를 admin.py에 등록하고 관리

  • record에 생성 여부 확인에 매우 유용하고 직접 레코드를 작성할 수고 있다.

  • CRUD 로직을 모두 관리자 페이지에서 사용할 수 있다.

  • 명령어 : python manage.py createsuperuser

    사용자 이름 (leave blank to use 'student'): admin
    이메일 주소:
    Password:
    Password (again):
    비밀번호가 너무 짧습니다. 최소 8 문자를 포함해야 합니다.
    비밀번호가 너무 일상적인 단어입니다.
    비밀번호가 전부 숫자로 되어 있습니다.
    Bypass password validation and create user anyway? [y/N]: y
    Superuser created successfully.
    

1. 커스터 마이징

1. list_display
 - admin 페이지에서 우리가 `models.py`에 정의한 각각의 속성(컬럼)들의 값(레코드)를 보여준다.
2. list_filter
- 특정필드에 의해 변경목록을 필터링 할 수 있게 해주는 Filter 사이드바를 추가한다.
- 표시되는 필터의 유형은 필드의 유형에 따라 다르다.
3. list_display_links
- 목록 내에서 링크로 지정할 필드 적용(설정하지 않으면 기본값을 첫번째 필드에 링크가 적용)
4. list_editable
- 목록 상에서 직접 수정할 필드를 적용
5. list_per_page
- 한 페이지에 표시되는 항목 수를 제어(기본 값: 100)

2. Django extensions

#참고사이트

https://django-extensions.readthedocs.io/en/latest/

  • Django-extension 은 커스텀 확장 tool이다.
  • Django app 구조로 되어 있기 떄문에 프로젝트에서 사용하기 위해서는 app 등록 과정을 거쳐야 한다.
  1. shell_plus

    #참고사이트

    https://django-extensions.readthedocs.io/en/latest/shell_plus.html#

    • 장고의 모든 import 값들을 가져온다.