Django CRUD
#참고문서
https://docs.djangoproject.com/ko/2.2/topics/db/models/
[TOC]
1.Crud
1.SQL 기본단어 정리
명령어 : pip freeze > requirements.txt
현재 설정 환경 저장.\
1.기본틀
- 테이블(table)
- PK : Primary Key(기본키)
- 열(Column),
- 행(row), 레코드
2.SQL
C: create
R: read
U: update
D: delete
2. ORM 객체 언어
- 번역기의 개념
- 장점
- 개발의 생산성이 높아 졌다.
- SQL을 몰라도 사용 가능하다.
- SQL 의 절차적인 접근이 아닌 객체 지향적 접근이 가능하다.
- 매핑정보가 명확하여 ERD를 보는 것에 대한 의존도를 낮출 수 있다.
- ORM은 독립적으로 작성되어 있고, 해당 객체들을 대활용 할 수 있다. 개발자는 객체에 집중함으로써 해당 DB에 종속될 필요 없이 자유롭게 개발할 수 있다.
- 단점
- ORM 만으로 완전히 거대한 서비스를 구현하기가 어렵다.
- 사용하기는 편하지만, 설계는 매우 신중하게 해야함.
- 프로젝트의 규모가 커질 경우 난이도가 올라가게 된다.
- 순수 SQL보다 약간의 속도 저하가 생길 수 있다.
- 이미 프로세스가 많은 시스템에서는 ORM으로 대체하기가 어렵다.
- ORM 만으로 완전히 거대한 서비스를 구현하기가 어렵다.
- 결론
- 생산성!
- ORM을 사용하여 얻게 되는 생산성은 약간의 성능저하나 다른 단점들을 상쇄할 만큼 뛰어나기 때문.
- 장점으로 인한 생산성 증가가 훨씬 비중이 크기 때문에 현대에는 대부분의 프레임워크들이 ORM을 사용하고 있다.
- 즉, 우리는 DB를 객체(objec) - 인스턴스(instance)로 조작하기 위해서 ORM을 배운다.
1. 모델
-
개념
- 모델은 단일한 데이터에 대한 정보를 가지고 있다.
- 필수적인 필드(컬럼, 열)와 데이터(레코드, 행)에 대한 정보를 포함한다. 일반적으로 각각의 모델(클래스)는 단일한 데이터베이스 테이블과 매핑(연결, 연동)된다.
- 모델은 부가적인 메타데이터를 가진 DB의 구조(layout)를 의미
- 사용자가 저장하는 데이터들의 필수적인 필드와 동작(behavior)을 의미
-
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에 대한 모든 것들을 볼 수 있다.
-
-
model 로직
- DB 컬럼과 어떠한 타입으로 정의할 것인지에 대해 django.db 모듈의 models의 상속을 받아서 적용된다.
- 각 모델은
django.db.models.Model
클래스의 서브 크래스로 표현된다.(자식클래스) - 모든 필드는 기본적으로 NOT NULL 조건이 붙는다.(NULL 값이 들어갈 수 없다.)
- 각각의 클래스 변수들은 모델의 데이터 베이스 필드를 나타낸다.
-
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 변경 시 작성 순서
-
models.py
: 작성 및 변경(생성/수정) -
makemigrations
: migrations 파일 만들기(설계도) -
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 조작)
-
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)
-
데이터 객체를 만드는 (생성, CRETE)하는 3가지 방법
-
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>)
-
두번째 방식
>>> article = Article(title='second', content='django!!') >>> article.save()
-
세번째 방식
- 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
- 유효성 검사
- save 전에
full_clean()
메서드를 통해 article 이라는 인스턴스 객체가 검증(validation)에 적합한지를 알아 볼수 있다. models.py
에 필드 속성과 옵션에 따라 검증을 진행한다.(기본값:blank=False
,null=False
)
- save 전에
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
모델 삭제 방법
- 0001 ~~ 번호 붙은 py 다 날리기
- db.splite3 날리기
- 처음부터 다시 하기
# 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 오류
- 빈 값
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.
- 중복값
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 등록 과정을 거쳐야 한다.
-
shell_plus
#참고사이트
https://django-extensions.readthedocs.io/en/latest/shell_plus.html#
- 장고의 모든 import 값들을 가져온다.