공부 기록

[멋사] django로 블로그 만들기(글 쓰기, 읽기, 수정, 삭제 기능)

by 너나나

장고에서 기본적으로 사용되는 디자인 패턴 : M(model) V(view) T(template)

장고에서 우리 눈에 템플릿(tamplates - 우리가 보는 html화면)을 띄워주는 과정은

  1. url로 요청을 받아서 우리가 url을 적어준 urls.py로 가서 해당 요청에 맞는 url을 분석
  2. 우리가 적어줬던 views 함수이름. 을 통해서 해당 url에 연결된 view로 가서 함수를 찾아서 기능을 수행
  3. view에서는 로직을 실행하면서, 만약 우리가 로직에 데이터베이스 관련 처리가 필요하면 model을 통해 처리하고 그 결과를 반환
  4. 마지막으로 view는 최종 결과로 templates(HTML 파일)을 클라이언트, 즉 우리에게 보내서 띄워줌

이런 과정을 거친다!!

그림으로 요약한 MVT 패턴

우리가 models.py에 파이썬 클래스를 이용해서 데이터에 대해서 적어주면 장고는 알아서 얘들을 데이터베이스의 테이블로 번역해서 우리에게 필요한 데이터들을 제공해준다!! 그래서 우리는 SQL문 이런거 몰라도 장고가 알아서 맵핑 해준다!!!!

https://guiyum.tistory.com/79 여기에 기초를 설명해놨으니까 urls.py, views.py이런 애들 여기서 보기!! 여기서는 설명 생략!!

CRUD : Create, Read, Update, Delete
글 쓰기, 읽기, 수정, 삭제가 가능한 페이지를 만들어 보자!!!!

python -m venv myvenv # 가상환경 설치 myvenv/Scripts/activate # 가상환경 실행 pip install django # 장고 설치 django-admin startproject blog # 장고 프로젝트 생성 cd blog # blog 폴더 안으로 들어감 python manage.py startapp main # app 생성 python manage.py runserver # 실행

새 폴더를 만들고 vs code를 실행시켜 터미널에 여기까지 치고 링크 나오면 ctrl+클릭해 로켓창을 띄우면 프로젝트 만들기 성공!! 이제 본격적으로 내 블로그를 만들어보자!!!

먼저 새 app을 깔았으니까 프로젝트안의 settings.py로 들어가(blog/settings.py) 새로 만든 app 이름을 등록

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'main', # 새로운 app ]

이제 블로그로 들어가면 제일 먼저 보이는 전체 글 보기 페이지라고 해야하나?? 이런 맨 처음 html을 띄워주기 위해서 templates 폴더를 app 안에 만들고 index.html(첫페이지)를 만들고 이 페이지를 띄울 함수를 views.py에 들어가 적어주겠다!! 그리고 urls.py에 index경로를 만들어주고 실행하면
index.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>MY BLOG</h1> <div class="create"> <button type="button" class="create-btn"><a href="">글 작성</a></button> </div> </body> </html>
# views.py from django.shortcuts import render # Create your views here. def index(request): return render(request,'index.html') 
# urls.py from django.contrib import admin from django.urls import path from main import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.index, name = "index"), ]

하찮은 블로그

이렇게 눌러도 아무일없는 버튼 하나만 놓인 블로그가 만들어진다.. 이제 진짜 글 작성 기능을 하게 만들어보자!!
글 작성 폼을 담아줄 forms.py라는 파일을 하나 만들고 우리가 받아와야되는 정보들을 models.py에 적을 것이다!!
models.py로 먼저 가서 글 작성 폼 Write라는 모델을 하나 생성해주자.

# models.py from django.db import models class Write(models.Model): title = models.CharField(max_length=100) # 제목 contents = models.TextField() # 내용 updated_at = models.DateTimeField(auto_now=True) # 글 작성 시간

제목, 내용, 시간을 받아오는 모델을 Write라는 이름으로 생성했다.
CharField : 짧은 문자들을 입력할때 쓰는 필드로 max_length를 반드시 가져야 한다!! (최대 작성가능한 길이)
TextField : 많은 문자들을 입력할 때 쓰는 필드. max_length 굳이 가질 필요 없음
DateTimeField : 날짜와 시간을 입력하는 필드. auto_now=True를 주면 현재 날짜와 시간을 자동으로 받아옴

이렇게 모델을 생성해줬으면 터미널창으로 가서

python manage.py makemigrations python manage.py migrate

이 두 명령어를 사용해서 장고가 알아서 데이터베이스에 대한 내용을 인식하게 만들어준다!!
그러고 이제 forms.py에 가서

from django import forms from .models import Write class WriteForm(forms.ModelForm): class Meta: model = Write fields = '__all__'

코드를 적어주면 Write 모델의 모든 fields를 폼에 담을 수 있다.

그럼 이제 글 작성 버튼을 누르면 뜨는 글을 작성하는 페이지인 create.html 파일을 만들어주고 views.py와 urls.py에 함수를 쓰자!!

create.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <form method="POST"> {% csrf_token %} {{create_form.as_p}} <input type="submit" value = "제출"> </form> </body> </html>
# views.py from django.shortcuts import render,redirect,get_object_or_404 from .models import Write from .forms import WriteForm def index(request): return render(request,'index.html') def create(request): if request.method == "POST": create_form = WriteForm(request.POST) if create_form.is_valid(): create_form.save() return redirect('index') # 글 쓰고 인덱스로 감 else: create_form = WriteForm() return render(request,'create.html',{'create_form':create_form})

POST는 요청 방식인데 내부적인 처리에서 클라이언트가 서버에게 웹페이지를 보여달라고 말하는 거를 요청이라고 부른다. 그러고 서버가 클라이언트에게 요청받은 것에 대한 대답으로 웹페이지 내용을 표현하기 위해 html문서로 주는것을 응답이라고 부른다!! 요청 방식에 POST도 있고 GET도 있는데 GET방식은 url에 데이터가 표시돼고 POST방식은 안보인다!! 우리가 쓴 내용이 url상에 표시되면 머쓱하니까 POST요청 방식으로 처리했다.

여튼 POST요청이 들어오면 POST방식으로 적힌 데이터들의 유효성을 검사하고 저장해주는 함수를 작성한것이다.

# urls.py from django.contrib import admin from django.urls import path from main import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.index, name = "index"), path('create/', views.create, name="create") ]

그리고 아까 index.html 파일에 create.html과 버튼을 연결해주자!!

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" type="text/css" href="{% static 'css/index.css' %}"> </head> <body> <h1>MY BLOG</h1> <div class="create"> <button type="button" class="create-btn"><a href="{% url 'create' %}">글 작성📝</a></button> </div> </body> </html>

body의 h1태그 밑에 이렇게 수정했고 index.html파일도 좀 꾸며줄려고 css파일도 연결했다.
django project에 static폴더를 만들고 그 안에 css 폴더를 만들어 index.css파일을 만들었다.

body{ margin: 0; padding: 0; } *{ text-decoration: none; } h1{ margin-left: 80px; } .create{ margin:50px 0 0 900px; } .create-btn{ background-color: cadetblue; width: 150px; height: 50px; text-align: center; border-radius: 10px; border-style: none; font-size: large; } .create-btn a{ color: white; } .write-wrapper{ width: 100%; } .write{ margin: 100px; padding: 50px; width: 60%; height: 200px; border: 1px solid black; } .write div{ margin-top: 10px; }

그리고 settings.py에 import os를 해주고 밑으로 쭉쭉 내려 STATIC_URL 밑에

STATIC_ROOT = os.path.join(BASE_DIR,'static')

이거 한줄을 써준다!! 장고에서 static파일을 효율적으로 관리해주기 위해서 경로를 쓴다고 한다.
index.html 맨 위에 장고에서 템플릿을 불러올때 쓰는 문법인 {%%}안에다 load static이라고 적어서 css를 연결해줘야한다.

{% load static %}

그러고 다시 runserver해보면

글 작성하기를 누르면
이렇게 작성하는 페이지가 뜬다!!

이렇게 제출을 누르면 아무일도 일어나지 않은 index.html창이 뜨는데 우리가 index.html에 이 적은 내용을 뿌려주는 코드는 안적었으니까 당연히 아무 내용이 없다!!!
index.html로 다시 가서 내용을 띄워주는 코드를 작성하자.
먼저 views.py로 가서

def index(request): all_write = Write.objects.all() return render(request, 'index.html',{'all_write':all_write})

all_write에 모델에 있는 모든 오브젝트를 다 가져왔고 all_write를 딕셔너리 형태로 render할때 써서 사용할 수 있게 만들었다!! 그러고 index.html로 가서

 <div class="write-wrapper"> {% for write in all_write %} <div class="write"> <a href="#"> <div>{{write.title}}</div> <div>{{write.contents}}</div> <div>{{write.updated_at}}</div> </a> </div> {% endfor %}

body 안의 버튼 밑에 내용을 적어줬다. 저기 나중에 글을 누르면 자세한 페이지를 띄우게 할려고 a태그를 넣었고 for문으로 all_write에 있는 것들을 하나하나 분리해서 적어주었다!!

이러고 다시 아까 띄운 창을 새로고침 하면!!!!

아까 작성한 글이 드디어 보인다!!!!!!

성공!!! 근데 시간이 보면 우리나라 시간이랑 다른걸 볼 수 있는데 저거는 다른나라 시간이라 한국으로 바꿔야한다!!
settings.py로 가자아아아

LANGUAGE_CODE = 'en-us' TIME_ZONE = 'Asia/Seoul' USE_I18N = True USE_L10N = True USE_TZ = True

settings.py로 가서 쭉쭉 내려서 TIME_ZONE을 찾고 Asia/Seoul로 바꿔주면

우리가 작성한 시간으로 잘 바뀐걸 볼 수 있다!!

글 작성을 눌러서 두번째 글을 작성한것도 이렇게 잘 띄워진 것을 볼 수 있다!!
이제 게시글을 클릭했을때 내용을 보여주는 detail 페이지를 만들어보자!!


그 전에 알아야 할 개념이 primary key(기본키, pk)인데, 우리가 객체(작성된 글)을 생성했을 때 고유의 id 번호가 생긴다.
첫번째 글은 =1, 두번째 글은 =2 이런 식으로!!
그러니까 우리가 첫번째 글을 클릭했을때 첫번째 글의 detail 페이지를 띄워야 하고 두번째 글을 클릭했을 때 2번째 글의 detail 페이지를 띄워야 하는데, 각각 글을 생성했을 때마다 여러개의 detail페이지를 생성할 수 없으니까 우리는 pk값을 이용해서 하나의 detail페이지만 만들고 상황마다 이 pk 아이디에 해당하는 값을 detail페이지에 불러와주면 된다.

detail.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> 제목 : {{my_write.title}} <br> 내용 : {{my_write.contents}} <br> 작성 시간 : {{my_write.updated_at}} </body> </html>


우리가 id값을 보기위해 만든 페이지의 주소 뒤에 /admin이라는 경로를 추가해 관리자 페이지로 들어가보자!!

주소 뒤에 /admin 추가!!

그럼 이런 로그인 창이 뜨는데 관리자 계정을 우리가 먼저 만들어야한다.
터미널로 가서

python manage.py createsuperuser

명령어를 입력하고 username을 적고 email은 안적어도 되니까 적거나 그냥 엔터 쳐주고 password를 입력하고 한번더 입력해 확인하면 되는데 이때 password창은 입력해도 표시는 안되지만 입력은 된거다!!

이러고 runserver하고 다시 admin페이지로 가서 로그인 하면

이렇게 뜨는데 우리는 지금 모델 안의 오브젝트를 보고싶으니까
admin.py로 가서

from django.contrib import admin from .models import Write admin.site.register(Write)

이렇게 모델을 등록해준다!! 그러고 다시 admin 페이지로 들어가면

모델이 추가돼있고 클릭해보면

우리가 썼던 object들이 있다!! 오브젝트 옆에 괄호에 적혀있는 숫자가 이 오브젝트들의 pk값이다!!
이제 이 pk값을 이용해서 views.py로 가서 함수를 작성해주자!! 그전에 index.html로 가서

 <div class="write-wrapper"> {% for write in all_write %} <div class="write"> <a href="{% url 'detail' write.id %}"> <!-- 우리가 불러올 id값 들고오기 --> <div>{{write.title}}</div> <div>{{write.contents}}</div> <div>{{write.updated_at}}</div> </a> </div>

detail 페이지로 들어갈 링크를 걸어줄때 id값을 가져오기 위해 write.id값을 하나 불러와준다. 이러면 views.py에서 id값을 사용할 수 있다!!

# views.py def detail(request, write_id): my_write = get_object_or_404(Write, id=write_id) return render(request,'detail.html',{'my_write':my_write})

여기서 get_object_or_404 는 없는페이지에 대해서 404 에러를 띄운다는 것!!

#urls.py urlpatterns = [ path('admin/', admin.site.urls), path('', views.index, name = "index"), path('create/', views.create, name="create"), path('detail/<int:write_id>', views.detail, name="detail"), ]


detail 페이지에서 아이디 값인 숫자를 불러오기 위해서 저런식으로 urls.py에 적었다.
이러고 이제 페이지로 들어가 첫번째 글을 클릭하면

이렇게 detail page가 뜬다!!
이제 이 글을 수정도 하고 삭제도 할 수 있게 만들어야한다. 여기까지 했으면 수정 삭제는 진짜 쉽다!!!!

먼저 index.html에 수정, 삭제 버튼을 만들어 주자

{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <link rel="stylesheet" type="text/css" href="{% static 'css/index.css' %}"> </head> <body> <h1>MY BLOG</h1> <div class="create"> <button type="button" class="create-btn"><a href="{% url 'create' %}">글 작성📝</a></button> </div> <div class="write-wrapper"> {% for write in all_write %} <div class="write"> <a href="{% url 'detail' write.id %}"> <!-- 우리가 불러올 id값 들고오기 --> <div>{{write.title}}</div> <div>{{write.contents}}</div> <div>{{write.updated_at}}</div> </a> <div class="update-delete"> <a href="{% url 'update' write.id %}">수정하기</a> <a href="{% url 'delete' write.id %}">삭제하기</a> </div> </div> {% endfor %} </body> </html>

그러고 views.py에 함수를 추가해주겠다!!! 먼저 수정부터 해보자!!

# views.py def update(request, write_id): my_write = get_object_or_404(Write,id=write_id) if request.method == "POST": update_form = WriteForm(request.POST, instance= my_write) # create와 달리 기존 내용을 수정해야 하니까 instance로 받아옴 if update_form.is_valid(): update_form.save() return redirect('index') else: update_form = WriteForm(instance=my_write) # request 안받았을때는 그냥 띄워줘라 return render(request,'update.html',{'update_form':update_form})

얘는 create와 미리 만들어진 오브젝트를 들고오는 것만 다르다. create와 달리 기존 내용을 수정해야 하니까 instance로 받아온다!!
그러고 urls.py에 연결

# urls.py urlpatterns = [ path('admin/', admin.site.urls), path('', views.index, name = "index"), path('create/', views.create, name="create"), path('detail/<int:write_id>', views.detail, name="detail"), path('update/<int:write_id>', views.update, name="update"), ] 

수정하는 페이지를 띄워야하니까 update.html 파일도 만들어주자!! create와 동일하게 작성하면 된다!!

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <form method="POST"> {% csrf_token %} {{update_form.as_p}} <button type="submit" value="제출">제출하기</button> </form> </body> </html>


마지막 delete!!!!!
pk값을 들고와서 그 id를 가진 오브젝트를 지워주고 index.html로 돌아가면 된다!!

# views.py def delete(request, write_id): my_write = get_object_or_404(Write,id = write_id) my_write.delete() return redirect('index')

그냥 이렇게 지워주면 끝!! urls.py에도 등록해주자

path('delete/<int:write_id>', views.delete, name="delete"),


이러면 끝!!!!!!!!!!!! 우리가 만든 페이지를 확인해보면

이렇게 수정하기 삭제하기 버튼이 있다.
수정하기 버튼을 눌러보면

내가 쓴 내용이 나온다!!! 수정하고 제출해보자!!

수정

이렇게 첫번째 게시글이 잘 수정됐다!! 첫번째 게시글에 삭제하기 버튼을 누르면

첫번째 게시글이 삭제되고 두번째 게시글만 남게된다.

장고 CRUD 기능을 가진 블로그 만들기 끝!!!!!!!!!!!!!!!!

블로그의 정보

공부 기록

너나나

활동하기