Programming/Django & Python

Model & CRUD 장고 데이터베이스

Ariella 2021. 11. 18. 23:49
반응형

 


 

CRUD

 

Create 생성

Read / Retrieve 읽기 / 인출

Update 갱신

Delete / Destroy 삭제 / 파괴

 

 

CRUD 는 소프트웨어가 가지는 기본적인 데이터 처리 기능을 묶어 지칭하는 말이다.

글의 생성, 읽기, 수정, 삭제 기능으로 이해하자.

 

먼저, CRUD 기능을 구현하기 위한 토대인 DateBase를 생성하자.

여기서는 ORM (Object Relation Mapping)을 이용하는데

SQL문 없이 파이썬의 객체 지향적 방법을 이용해 DB를 간접적으로 조작하는 것을 의미한다.

 

 

 


 

 

 

1. DB 생성

 

1-1. models.py에서 DB 테이블 생성하기

from django.db import models

class BLog(models.Model):
    title = models.CharField(max_length=200)
    writer = models.CharField(max_length=100)
    pub_date = models.DateTimeField()
    body = models.TextField()
    
    def__str__(self):
    	return self.title
        
    def summary(self):
    	return self.body[:100]
  • from ~ import models
  • (models.Model)

--> Blog가 장고 모델인 것을 알려준다.

 

  • return self.title = self의 title 즉, 각자의 객체들은 자신의 제목으로 보여진다.
  • def summary(self): return self.body[:100] = summary라는 함수는 self의 body를 100자까지만 보여준다. 즉, 각자 객체들은 자신의 body내용을 100자까지만 보여주게 된다.

 

 

1-2. 모델 수정 시 수행해야 할 명령 (Terminal에 입력한다.)

#앱 내에 migration 폴더를 만들어서 models.py 변경 사항을 저장한다.
python manage.py makemigrations

#migration 폴더를 실행시켜 DB에 적용한다.
python manage.py migrate

 

 

 


 

 

 

2. admin에서 DB에 접근하기 위한 준비

 

2-1. admin.py에서 모델 등록 알리기

from .models import Blog

admin.site.register(Blog)

 

 

2-2. admin에 접근할 수 있는 user (superuser) 생성하는 명령 (Terminal에 입력한다.)

id, emil, password를 차례로 입력하는데 password는 입력값이 보여지지 않으므로 다 입력하면 엔터로 넘어간다.

python manage.py createsuperuser

 

 

2-3. 가상환경 구동 후 admin 접근해보기

  • 가상환경 구동 명령문
python manage.py runserver
  • 주소창 뒤에 "admin/" 입력
  • superuser로 로그인

admin에 Blog 라는 모델, DB가 잘 생성되어 있는 것을 확인해볼 수 있다. 해당 부분을 클릭하여 들어가면 models.py에서 구성했던 데이터 테이블의 형식을 볼 수 있다.

 

 

 

 


 

위에서 구축한 DB를 바탕으로 CRUD 기능을 구현해보자.

 

 


 

# Read

 

1. Blog 객체 받아오기

views.py

from .models import Blog

def home(request):
    blogs = Blog.objects.all()
    return render(request, 'home.html', {'blogs':blogs})

모델에서 Blog 라는 틀을 생성했었다. 

이 틀을 이용해 만들어지는 각각의 데이터들이 "객체"이다.

 

blogs = Blog.objects.all()

  • Blog 틀을 이용해 만들어진 객체들 '모두'를 blogs라는 이름의 변수에 담아준다.

 

return render(request, 'home.html', {'blogs':blogs})

  • 위에서 blogs라는 이름의 변수에 담았던 객체 묶음을 
  • 'blogs'라는 이름으로 home.html 에 보내준다.

 

 


 

 

2. URL 등록하기

 

urls.py

#'앱 이름'으로부터 views=함수목록을 불러온다.
from blog import views

urlpatterns = [
	path('', views.home, name="home"), #추가
    ]

views.py에서 생성한 함수를 실행(=호출)하기 위해서는 url이 필요하다.

  • url 뒤에 아무것도 입력하지 않았을 때,
  • views의 함수 중 home 을 실행한다.
  • 그리고 함수가 실행되게 하는 이 명령은 다른 곳에서 home 이라는 이름으로 실행할 수 있다.

 

 


 

 

3. template 등록 후 객체들을 불러오기

 

게시글 목록을 만들기 위해서 'blogs'에 담았던 객체들을 하나씩 불러와야 한다.

--> 데이터는 쿼리셋 형태로 전달받기 때문에 for문을 돌리며 하나씩 쪼개준다.

 

* 쿼리셋 = 전달 받은 모델의 '객체 목록'

 

home.html

<body>
<h1> BLOG PROJECT </h1>
    {% for blog in blogs %}
    	{{blog.title}}
        {{blog.writer}}
        {{blog.body}}
        {{blog.summary}} <a href="{% url 'detail' blog.id %}"...more</a>
	{% endfor %}
 </body>
  •  {% for blog in blogs %} = blogs (객체 목록)내 각각의 blog 객체들에 대해
  • {{blog.title}} / {{blog.writer}} / {{blog.body}} = blog "의" title, writer, body를 가져온다. (객체 내부는 . 을 통해 접근)
  • {% endfor %} = for문을 닫아준다. 
  • {{blog.summary}} = blog의 summary 함수를 호출하여 요약 효과를 적용한다.

 

<a href="{% url 'detail' blog.id %}"...more</a>

  • ...more이라는 글자에 url 을 링크하는데
  • detail 이라는 이름의 url에 blog의 id값을 전달한다. 

 

 


 

 

4. detail url 연결하기

urls.py

path('<str:id>', views.detail, name="detail"), #urlpatterns에 추가
  • home.html 에서 받은 id값을
  • views 의 detail 함수로 전달한다.
  • 위의 과정을 수행하고 싶다면 다른 곳에서 detail이라는 이름으로 불러오면 된다.

 

 


 

 

5. detail 함수 생성

views.py

from django.shortcuts import render, get_object_or_404

def detail(request, id):
    blog = get_object_or_404(Blog, pk=id)
    return render(request, 'detail.html', {'blog':blog}
  • get_object_or_404 를 사용하기 위해 상단에서 import 해준다.

 

blog = get_object_or_404(Blog, pk=id)

  • 매개변수(parameter)인 id 값에 해당하는 Blog데이터 있다면 blog 변수에 담는다.
  • 일치하는 데이터가 없다면 404 에러를 띄운다.
  • (pk=id) = 데이터를 구분하는 기준을 id값으로 한다.

 

PK = Primary Key 데이터베이스 테이블에서 각각의 데이터 값을 식별하기 위한 id 값
get_object_or_404 = 페이지 요청 시, pk값으로 클래스 값 즉, 데이터 값을 가져오고 없을 경우 404 에러를 띄운다.
Path Converter = (여러 객체를 다루는) 계층적 URL를 만들기 위해 사용<type:변수이름> 변수는 views.py로 전달된다.

 

 


 

 

6. detail html 페이지 생성

detail.html

<body>
    {{blog.title}}
    {{blog.writer}}
    {{blog.pub_date}}
    {{blog.body}}
</body>
  • 특정 id값과 매칭된 데이터인 blog의 객체 정보에 접근한다.
  • id와 매칭된 하나의 객체 정보에만 접근하기 때문에 for문을 돌릴 필요가 없다.
  • summary 함수를 호출하지 않았으므로 전체 내용이 보인다.

 

 

 

 

 

 


 

# Create

 

1. new.html 글 작성 페이지를 보여주는 함수 생성

views.py

def new(request):
    return render(request, 'new.html')

 

 

2. new 함수 URL 등록

urls.py

path('new/', views.new, name="new"),

 

 

3. new.html 글 작성 페이지 생성

new.html

<form action="{%url 'create'%} method="POST"
    {%csrf_token%}
    <p>제목: <input type="text", name="title"></p>
    <p>작성자 : <input type="text" name="writer"></p>
    본문 : <textarea name="body" id="" cols="30" rows="10"></textarea>
    <button type="submit">등록</button>
</form>

<form action="{%url 'create'%} method="POST"

  • form 태그의 action 속성은 폼 데이터를 서버로 보낼 때 도착하게 될 URL을 명시한다. 여기서는 urls.py에서 create이름으로 정의된 url로 데이터가 전송되도록 했다. (등록버튼을 눌렀을 때,)
  • POST 방식으로 안전하게 전달, 데이터 생성
  • {%csrf_token%} = 보안을 위해 필수로 기입해야 한다.
  • <input> 태그는 사용자가 다양하게 폼 태그에 입력할 수 있는 공간을 만들어준다. name 속성은 폼이 서버로 전달될 때 이름

 

cf) name & value 의 차이점?

더보기

name은 전달 받는 입장에서 값을 꺼낼 수 있는 키

name= 동호수, value 소포

동호수인 name이 안써있다면 우편물을 꺼낼 수 없다.

 

 

4. "new.html 의 폼에서 입력받은 데이터"를 "DB에 저장해주는 함수인 create"에 url 연결

urls.py

path('create/'. view.create, name="create"),
  • new.html 에서 입력되고 전달된 데이터가
  • views.py의 create 함수로 전달된다.

 

 

5. "DB에 저장해주는 함수인 create" 생성

views.py

from django.utils import timezone

def create(request):
    new_blog = Blog()
    new_blog.title = request.POST['title']
    new_blog.writer = request.POST['writer']
    new_blog.body = request.POST['body']
    new_blog.pub_date = timezone.now()
    new_blog.save()
    return redirect('detail', new_blog.id)
  • Blog 모델이라는 틀(클래스)로 new_blog라는 객체를 생성한다.
  • 생성된 new_blog 객체의 title, writer, body 칸에 POST 방식으로 받아온 값(즉, new.html의 폼에서 name="title", "writer", "body"로 받았던 input값) 을 넣어준다.
  • new_blog 객체의 pub_date 칸에는 timezone.now() 즉, 현재시간을 넣어준다.
  • 위와 같이 칸이 채워져 완성된 new_blog 객체를 저장한다.
  • 생성 후에 저장된 글을 보여주기 위해 detail 페이지로 redirect하는데
  • 새로 생성된 객체(글)의 id 값을 전달하여 "이 객체의" 디테일 페이지로 이동한다.
redirect
새로운 페이지를 만든 것이 아니라 기능만 수행하고 돌아갈 때. (상단에서 import 해주어야 쓸 수 있다.)
return redirect(돌아갈 url 이름, return value) 

 

 

 

 

 

 


 

# update

 

1. detail.html 에 수정 버튼 생성

<body>
    {{blog.title}}
    {{blog.writer}}
    {{blog.pub_date}}
    {{blog.body}}
    
    <a href="{% url 'edit' blog.id %}">edit</a> #수정 버튼 추가
</body>
  • edit 을 클릭하면 url 중 name=edit인 곳으로 연결되는데 
  • edit 페이지로 blog.id 블로그의 아이디(현재 페이지의 번호)를 전달한다.

 

 

2. urls.py에 path 추가

path('edit/<str:id>', views.edit, name="edit"), #추가
  • detail.html 에서 전달한 값이 url 을 타고 서버로 전송된다.
  • 이를 views.py에서 받아서 edit함수로 처리한다.

 

 

3. views.py 에서 edit 함수_수정할 객체를 찾는 함수 생성

def edit(request, id):
    edit_blog = Blog.objects.get(id=id)
    return render(request, 'edit.html', {'blog':edit_blog})

def edit(request, id):

  • url을 통해서 전달받은 id값

edit_blog = Blog.objects.get(id=id)

  • 블로그 클래스의 모든 객체들 중 이 전달받은 id값과 동일한 id값을 가진 객체를 찾고
  • 이 찾은 객체를 edit_blog라는 변수에 넣어준다.

return render(request, 'edit.html', {'blog':edit_blog})

  • 찾은 객체는 blog라는 이름으로 
  • edit.html 에 전달한다.

 

 

4. edit.html 글 수정 공간 생성

<h1> Update Blog </h1>

<form action="{%url 'update' blog.id %} method="POST"
    {%csrf_token%}
    <p>제목: <input type="text", name="title" value="{{blog.title}}"></p>
    <p>작성자 : <input type="text" name="writer" value="{{blog.writer}}"></p>
    본문 : <textarea name="body" id="" cols="30" rows="10" value="{{blog.body}}"></textarea>
    <button type="submit">등록</button>
</form>
  • 블로그의 title, writer, body를 {{}} 태그에 담아서 이전에 작성했던 내용을 띄워준다.
  • 띄워진 내용에서 수정을 마치면 등록 버튼을 누르고
  • 수정된 내용이 update url 을 통해서 전달된다.

 

 

5. urls.py 에 "update" path 추가

path('update/<str:id>', views.update, name="update"),
  • 전달받은 blog.id 값을 views.py의 update 함수로 전달한다.

 

 

6. views.py에 update 함수 = 수정된 내용을 저장해주는 함수 생성

def update(request, id):
    update_blog = Blog.objects.get(id=id)
    update_blog.title = request.POST['title']
    update_blog.writer = request.POST['writer']
    update_blog.body = request.POST['body']
    update_blog.pub_date = timezone.now()
    update_blog.save()
    return redirect('detail', update_blog.id)
  • 기존 글의 제목, 작성자, 내용, 작성일을 모두 수정한 내용을 바꿔준다.
  • POST 방식으로 전달한 form 의 내용을 가져온다.
  • 저장한 후 detail 페이지로 돌아가서 수정 결과를 보여준다.

 

 

 

 

 

 


 

# Delete

 

1. detail.html 에 삭제 버튼 생성하기

detail.html

<body>
    {{blog.title}}
    {{blog.writer}}
    {{blog.pub_date}}
    {{blog.body}}
    
    <a href="{% url 'edit' blog.id %}">edit</a>
    <a href="{% url 'delete' blog.id %}">delete</a> #삭제 버튼 추가
   
</body>
  • delete 을 클릭하면 url 중 name=delete인 곳으로 연결되는데 
  • delete로 blog.id 블로그의 아이디(현재 페이지의 번호)를 전달한다.

 

 

2. urls.py 에 path 추가

path('delete/<str:id>', views.delete, name="delete"),
  • 전달받은 blog.id 값을 views.py의 delete 함수로 전달한다.

 

3. views.py 에 delete 함수 추가

def delete(request, id):
    delete_blog = Blog.objects.get(id=id)
    delete_blog.delete()
    return redirect('home')

delete_blog = Blog.objects.get(id=id)

  • Blog 모델이라는 틀(클래스)로 생성된 객체 목록 중 전달받은 id값과 일치하는 id를 가진 객체를 delete_blog라 한다.

delete_blog.delete()

  • 일치하는 id값의 객체인 delete_blog에 delete 함수를 수행한다.

return redirect('home')

  • home.html 로 돌아간다.

 

 

 

 

 

 


 

reference)

https://www.nextree.co.kr/p8428/

http://tcpschool.com/html-tag-attrs/form-action

반응형