Django — CRUD 기능 구현

inviisiblegangb0ss.eth
12 min readJul 7, 2019

--

방학숙제1

https://347glnm8vja.typeform.com/c/AMTeQE8A

1. (만들기 전에) 일단 CRUD 란 무엇인가?

CRUD는 데이터를 처리하는 네가지 방식 create, read, update, delete을 부르는 말이다. 웹 프레임워크를 만들때 필수적으로 작동해야 하는 기능이다.

밑의 코드카데미의 글에 아주 잘 설명되어있다.

2. (본격적으로 만들기 전에) 일단 settings.py 설정

  • django project와 app 생성, 등록까지
$ python -m venv 'myvenv' #가상환경 생성$ source myvenv/scripts/activate # 가상환경 실행(myvenv) # 가상환경 켜짐$ pip install django # django 설치$ django-admin startproject 'crudnote' #프로젝트 생성# 이때 manage.py가 위치한 프로젝트 안(BASE_DIR)으로 들어간다. $ python manage.py startapp 'blog' # app 생성$ python manage.py runserver # http://127.0.0.1:8000/# vscode에 있는 liveserver 등 extension들도 로컬 서버를 지원한다. 

앱 등록하기 on ‘settings.py’

INSTALLED_APPS = [
```
'blog.apps.BlogConfig', # 이게 정석이다. 하지만 굳이 이렇게 안하고 그냥 'blog' 이렇게만 해도 된다.
```
]

templates, staticfiles를 불러올 위치를 정해주었다.

app을 어차피 하나만 쓸거라서 템플릿 위치를 프로젝트 폴더 안의 ‘templates’ 로 일원화했다.
static 파일을 불러올 위치도 역시 프로젝트 폴더 안의 ‘static’으로 정해주었다. ( static 파일들은 어차피 배포할때 collectstatic 하면 하나의 폴더 아래로 모두 모인다.)

3. models.py 쓰기

models.py 에 만들고싶은 data를 적는다.

이때 각 field의 default값은 ‘null=False’로 지정되어있다. 따라서 admin/사용자 페이지에서 데이터를 입력할때 빈칸으로 남겨두면 자동으로 required(필수 입력) 메세지를 띄운다.

  • content 필드에서 빈칸을 허용하려면 null=True로 할수도 있다. 하지만 나중에 처리하는데 값이 없으면 어려움이 있을까봐 default=``로 놔서 ` ` (spacebar 한칸)만큼 데이터가 기본으로 들어가있게 했다.
  • ‘ __str__’ 함수를 쓰면 제목을 띄울때 사용자에게 입력받은 문자열을 그대로 나타나게 한다. 이걸 지정해주지 않으면 역시 admin페이지에서 장고 default 설정대로 일괄적으로 부여된 게시물 넘버가 나온다.
  • models.py 쓰고나서 migration : DB에 등록하기
$ python manage.py makemigrations
$ python manage.py migrate
  • ‘admin.py’ 에 들어가서 앞서 models.py에 작성한 class Post를 등록해준다. 장고에서 기본으로 제공하는 admin 페이지에 ‘Posts’라는 이름 아래 Post의 객체들이 나온다. (이때 admin 페이지에 접속하려면 superuser 계정을 생성해줘야 한다. )
admin.site.register(Post)
blog/models.py
admin.py에 Post를 등록해준다.
/admin 페이지 안에서 Posts를 관리할 수 있게 되었다.

4. urls.py — views.py — templates

장고 튜토리얼을 보면 보통은 기능을 하나씩 구현할때마다 ‘url — view — template’ 순으로 제작하는 것 같다. 하지만 나의 경우 이런 순서대로 만들고나면 변수 이름을 틀려서 에러를 내거나 다음에 뭘 해야하는지 자꾸 까먹는 불상사가 생겼다.

괜히 일을 두번씩 하게 되기에 (MTV 공부할겸) 노트에다가 필요한 ‘url — view — templates’ 이름과 구조를 모두 써놓고 시작했다.

  • ‘templates’ 폴더에 필요한 html 파일들을 만들고 → 1. urls.py를 먼저 쓴다. → 2. views.py에 가서 html을 띄우는 return 함수 작성한다. → 3. 각 url-view에 맞는 template이 정상적으로 나오는지 확인했다.
  • url을 불렀을때 해당 template이 정상적으로 호출되면 → forms.py를 작성하고→ views.py에 가서 return template 만 해놓았던 함수를 완성해주었다.
  • 자세한 코드 설명은 또 나중에 쓰면 까먹을까봐 옆에 주석으로 달아놓았다.
project/urls.py
project/app/urls.py

5. forms.py 쓰기

아까 admin page에서 Post 모델이 잘 작동하는걸 봤다. 이제는 admin 접근 권한이 없는 일반 사용자도 게시물을 생성, 수정, 삭제 할 수 있게 해 보겠다. 장고에서는 form을 통해 일반 사용자로부터 models.py 구조에 해당하는 데이터를 입력받을 수 있다.

forms.py

  • ModelForm을 쓰면 일반 Form을 쓸 때보다 할 일이 많이 줄어든다. label 이름 등 더 수정할게 없다면 ModelForm을 그대로 쓴다. class Meta에 사용자로부터 입력받고싶은 field를 지정해주면 django가 알아서 form을 생성한다.
  • 앞서 models.py에서 datetimefield는 ‘auto_now_add=True’를 줘서 자동으로 가져오게 했으니까 굳이 form에서 직접 입력받을 필요가 없다. django documentation에 가면 각 field가 어떤 데이터 타입인지 아주 잘 설명해놓았다.
blog/forms.py

views.py 완성하기

자세한 코드 설명은 나중에 쓰면 또 까먹을까봐 옆에 주석으로 달아두었다.

project/app/views.py
project/app/views.py

6. templates 작성하기

아까 써준 urls.py와 views.py에 따라 template을 완성한다.

  • 이때 주의할 점은 url-template 관계는 1:1 대응이 아니라는것이다. 아까 template을 처음 만들때는 delete 기능을 위해 필요할것 같아 ‘delete.html’ 을 만들었다. 그런데 템플릿을 불러오는건 url이 아니라 view에 정의된 return 함수가 하는것이다.
  • base.html을 만들어서 각 template에 확장을 시켜주었다. 이렇게 하면 html 파일마다 공통적으로 들어가는 요소들(style, elements,… etc. )등을 매번 각각 써줄 필요가 없다. 각 template마다 필요한 코드는 {% block ~~ %} 태그를 써서 그 안에 써 주었다.

templates/create.html (게시물 생성)

  • template에서 form태그 안에 {{ form.as_p }} 를 적으면 앞서 forms.py에서 fields =[]에 적은각각의 필드를 p태그를 씌워 자동으로 만들어준다. <p> 말고 table 등 다른 형식으로도 만들 수 있다. 개인적으로 css등 스타일을 적용할때는 p태그를 쓰는게 수정하기 더 편했다.
  • {% csrf_token %}은 장고에서 기본으로 제공하는 보안 수단이다. 사용자가 form에 입력한 값이 외부에서 보이지 않게 한다. (이걸 적용하지 않고 그냥 submit을 눌렀더니 csrf가 없다는 에러 페이지가 나왔다.)
  • 보안을 말하자면 사용자에게서 정보를 입력받을때는 GET방식보다 POST 방식을 쓰는게 더 낫다고 한다. GET방식을 쓰면 url에 사용자가 입력한 데이터가 그대로 붙어서 나온다. (다만 실제 사용자가 있는 사이트라면 당연히 보안 수단을 따로 쓰고있겠지. 이렇게 간단하게 설명이 끝나지는 않을 것이다. )
templates/postcreate.html

templates/postupdate.html (게시물 수정)

views.py에서 이미 입력된 내용을 불러오는것 이외에는 앞서 create과 내용이 똑같다.

  • update를 논하자니 시간에 대해 말해야겠다. 아까 모델에서 DateTimeField를 지정할때 auto_now_add =True 를 썼었다. 이렇게 하면 몇번을 수정하든지 게시물이 최초 생성될때 시간만 반영한다. 게시물을 수정할때 시간은 갱신되지 않는다.
  • 대신 auto_now=True 를 쓰면 게시물이 수정될때마다 시간도 같이 갱신된다. 나는 글을 빨리 쓰는대신 수정을 많이 하는 편이다. 따라서 남들이 봤을때 시간이 자꾸 바뀌어있으면 부끄러울까봐 일부러 갱신이 안되게 해 놓았다.
templates/postupdate.html

template/postdetail.html (게시물 상세보기)

  • django에서 내용을 표시하는 태그는 {{ class.object }} 보통 이런 형식으로 작성한다.
  • 게시물 상세보기 페이지 안에 ‘수정하기’ ‘삭제하기’ 버튼을 만들어주었다.
  • 이때 삭제하기 기능은 따로 html을 만들지 않았고 ‘삭제하기’ 버튼에 delete 함수가 실행되는 url을 연결해주었다.
<a href="{% url 'delete' post.pk %}"><input class="btn btn-info" type="button" value="삭제하기"></a>
postdetail.html
postdetail.html

templates/postslist.html (게시물 리스트)

  • table 형식은 bootstrap 사이트에 가니 깔끔한게 있어서 그걸 사용했다.
  • {% for ~ in ~ %} 태그를 쓰면 for문을 돌며 db에 있는 게시물들을 띄워준다. 여기서는 posts.all을 써서 나의 db에 있는 post들을 처음부터 끝까지 돌았다. forloop 등의 태그를 쓰면 for문이 도는 loop 범위를 정해줄 수도 있다고 한다. (나중에 써보고 어떻게되는지 또 쓰겠다. )
  • DateTimeField, CharField 등은 built-in 태그를 써서 template에 표시하는 방식을 정해줄 수 있다. 이걸 쓰면 views나 models에서 로직을 복잡하게 따로 쓰지 않아도 된다.
  • 제목(title)을 클릭하면 해당 게시물의 detail page로 들어가는 링크를 걸어주었다. 여기에 pk(primary key)를 꼭 써주어야 해당 게시물 번호의 url로 들어갈 수 있다.
<a href="{% url 'detail' post.pk %}">{{ post.title }}</a>
postslist.html (내용이 길어서 block 태그 안의 코드만 캡처했다.)

자 이렇게 다 써주면 완성!!!!

게시물 리스트: 빠른 시일내에 자스를 써서 글자가 아니라 테이블에 링크를 걸어봐야지
게시물 상세페이지
게시물 등록하기

깃헙에 매주 계속 업데이트할 예정입니다. 심심할때 보시면 재밌을듯 합니다. 놀랍게도 각 코드에 주석이 아주 꼼꼼히 달려있습니다.

어디서든 틀린 점, 개선할 부분을 발견하신다면 알려주세요. 사소한 띄어쓰기나 오타라도 괜찮습니다. 코딩할때는 글자 하나라도 잘못치면 큰일나니까요. 알려주시면 저의 공부에 큰 도움이 됩니다. :D

--

--

Responses (1)