이번 프로젝트는 3. Model & Admin에서 만들었던 프로젝트의 연장선이다.
가상환경 생성 및 실행, project 생성, app 생성, settings.py 등록까지 모두 마쳐주었다면
이번엔 bootstrap을 활용해서 좀 더 깔쌈한 인터페이스를 만들어보자.
bootstrap 홈페이지의 document에서 다음의 코드를 가져온다.
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Blog Project</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNavAltMarkup">
<div class="navbar-nav">
<a class="nav-link active" aria-current="page" href="#">Home</a>
<a class="nav-link" href="#">Features</a>
<a class="nav-link" href="#">Pricing</a>
<a class="nav-link disabled">Disabled</a>
</div>
</div>
</div>
</nav>
HTML
복사
전체 코드 작성 후 css 설정까지 해주면, 다음과 같은 페이지를 볼 수 있다.
view 만들기
이제 view를 만들어준다. blog 폴더 안의 views.py 파일을 열어 요청이 들어오면 home.html파일을 여는 함수를 만들어 보자. 물론 미리 만들어놨다.
이 과정이 끝났으면, URLconf 연결까지 마무리 해준다.
Navbar 항목이 왼쪽 정렬된 모습이 살짝 불편해서 우측 정렬 해주었다.
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="#">Blog Project</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNavAltMarkup">
<div class="navbar-nav ml-auto">
<a class="nav-link active" aria-current="page" href="#">Home</a>
<a class="nav-link" href="#">Blog</a>
<a class="nav-link" href="#">About</a>
</div>
</div>
</div>
</nav>
HTML
복사
model 만들기
•
제목
•
본문
•
작성일자
3가지를 넣어 model을 만들어 보자.
model을 만들었다면, 앞에서 배웠듯
1.
models.py에서 코드 작성
2.
python manage.py makemigrations 을 통해 migration 만들기
3.
python manage.py migrate 을 통해 데이터베이스에 적용하기
에 대한 내용을 잘 기억하고 적용해야한다.
admin 만들기
createsuperuser 명령어로 admin을 생성하고, admin.site.register()으로 admin 사이트에 Blog라는 클래스(model)를 등록해준다.
view로 데이터 가져오기
model을 생성하고 데이터를 넣었으면 이걸 template로 보내서 보여줘야한다. view를 통해 데이터를 가져온다. blogs 변수에 쿼리셋을 등록한다. 이후 render에서, blogs라는 변수를 template에서 쓸 때 blogs라는 이름으로 가져오겠다고 명명하는 작업을 해준다.
from django.shortcuts import render
from .models import Blog
# Create your views here.
def home(request):
blogs = Blog.objects
return render(request, 'blog/home.html', {'blogs': blogs})
Python
복사
여기까지가 기존 3. Model&Admin에서 배운 내용들이다.
다음은 블로그에 여러 기능들을 추가해보자
Detail 페이지 만들기
admin 페이지에서 게시글 작성, 게시글의 제목과 날짜, 내용을 화면에 출력하는 작업까지 성공적으로 해냈다. 그런데 만약 게시글 내용이 너무 길어지게 된다면 어떻게 될까?
아마 페이지가 그 게시물의 내용으로만 가득차서 다른 게시물은 올라와있는지 어떤지도 보이지 않을 것이다. 깔끔한 페이지를 위해 more 버튼을 눌렀을때 자세한 내용을 보여주는 detail.html을 띄우도록 해보자.
template 추가하기
detail.html을 추가해주고 우선 간단히 표시만 해둔다.
URLconf 연결
다음과 같이 작성을 해준다.
<int:blog_id>라고 적힌 부분은 각 게시물의 id 값이 들어갈 공간이다.
그게 뭔데
우리의 게시글이 100개라고 해서 100개의 path를 다 적어줄 필요는 없다.django는 각 게시물들의 id값을 전달받아, 알아서 url을 디자인 해주기 때문이다.
urls.py에서 detail이라는 함수에 blog_id라는 인자를 넘겼으니 view.py의 detail함수는 blog_id를 전달받게 될 것이다.
view 만들기
from django.shortcuts import render, get_object_or_404
from .models import Blog
# Create your views here.
def home(request):
blogs = Blog.objects
return render(request, 'blog/home.html', {'blogs': blogs})
def detail(request):
blog_detail = get_object_or_404(Blog, pk=blog_id)
return render(request, 'blog/detail.html', {'blog': blog_detail})
Python
복사
먼저 import render, get_object_or_404 라고 수정해준다. render뒤에 콤마찍고 get_object_or_404를 적어주면 된다.
get_object_or_404 : object를 가져오고 없으면 404 에러를 띄우라는 내용의 함수. 안에 모델명(대문자로 시작)과 불러올 blog 게시글의 id값을 적어 주면 된다. 여기서 게시글의 id가 pk가 된다.
위의 detail 함수는 request와 blog_id를 함께 받아 해당 데이터를 넘겨준다.
urls.py에서 받아달라고 인자를 넘겼으니 detail함수가 blog_id를 받아오는 것을 확인 할 수 있다. 아, view는 urls.py에 적었던 pk를 식별한다. 그렇기 때문에 urls.py와 변수명이 다르면 오류가 뜨게된다.
이제 모델에서 id기준으로 데이터를 가져와, 있으면 보여주고 없으면 404 에러를 띄워준다. id 값은 만든적 없다고 걱정할 필요없다. django가 기본으로 생성해준다.
127.0.0.1:8000/blog/1/ 로 접속해준다.
그럼 이런 페이지가 뜬다. 만약 127.0.0.1:8000/blog/4/와 같이 현재 작성해놓은 글의 인덱스가 아닌 숫자를 입력하면,
이렇게 404 에러가 뜬다. 지금 작성한 글은 3개이기 때문이다.
이제 home.html에서 출력했던 게시글 목록의 내용을 100글자만 보여주고, 그 뒤에 more라는 글자를 붙여 링크를 타고 detail을 볼 수 있도록 해보자.
model 수정하기
model에 필요한 함수를 추가해준다.
def summary(self): # 글 내용 요약 함수
return self.body[:100]
Python
복사
위와 같은 함수를 추가했다. self 자리에 Blog가 들어갔다고 생각하면, return에서 얘기하는 건 Blog라는 클래스에 정의된 body에서 100글자만 출력하라는 의미이다.
template 고치기
위처럼 model 안에 새로운 함수를 정의해줬으니 template에서 새로 만든 친구를 불러와 보자. home.html에서 {{ blog.body }} 부분을 {{ blog.summary }} 로 수정해준다.
그러면,
이렇게 나온다.
그런데 줄여진게 아니라 그냥 짤린것 처럼 나오니 뒤에 ...더보기 를 추가해서 누르면 본문으로 넘어가게 만들어보자.
<p>{{ blog.summary }}<a href="{% url 'detail' blog.id %}">....more</a></p>
HTML
복사
이런식으로 나온다.
그럼 home과 detail페이지를 bootstrap을 사용해서 좀 더 그럴싸하게 만들어보자.
template 수정하기
<!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>detail</title>
<!-- CSS CDN -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'home' %}">Blog Project</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNavAltMarkup">
<div class="navbar-nav ml-auto">
<a class="nav-link active" aria-current="page" href="{% url 'home' %}">Home</a>
<a class="nav-link" href="#">Blog</a>
<a class="nav-link" href="#">About</a>
</div>
</div>
</div>
</nav>
<br>
<div class="container">
<h1>{{ blog.title }}</h1>
<p>{{ blog.pub_date }}</p>
<p>{{ blog.body }}</p>
<a href="{% url 'home' %}">돌아가기</a>
</div>
<!-- JavaScript Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
</body>
</html>
HTML
복사
글을 하나 더 추가했다. 세부 페이지로 들어가보면 다음과 같은 페이지가 나오게 된다.
게시글 등록 페이지 만들기
블로그 글을 작성할때마다 url에 직접 /admin이라고 치고 접속하는 방법이 일반적인 방법은 아니기에, 글을 작성하는 페이지를 만들고, 거기에서 작성을 하면 home에 추가되게끔 만들어 보자.
template 만들기
블로그 내용을 입력하는 화면을 만든다. 제목과 본문 내용을 입력받아야한다.
또, Navbar에 ‘글쓰기’ 탭을 추가해보자.
<!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>home</title>
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{% url 'home' %}">Blog Project</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="{% url 'home' %}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">글쓰기</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
</ul>
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
<br>
<div class="container">
<form action="">
<h4>제목: </h4>
<input type="text" name="title">
<br>
<br>
<h4>본문: </h4>
<textarea cols=40 rows=10 name="body"></textarea>
<br>
<br>
<input class="btn btn-dark" type="submit" value="제출하기">
</form>
</div>
</body>
</html>
HTML
복사
이런식으로 나오면 성공이다.
View 만들기 & URL 설정하기 & template에 링크 넣기
이젠 너무 익숙한 설정들이다.
def write(request):
return render(reuqest, 'blog/write.html')
Python
복사
path('blog/write/', blog.views.write, name="write"),
Python
복사
이제 template에 {% url 'write' %}를 알맞게 잘 넣어보자.
올바른 url로 페이지가 잘 출력된다.
제출하기 버튼 작동시키기
제출하기 버튼을 누르면 내가 입력한 데이터는 DB에 저장되고, home 화면을 볼 때 보여져야 한다. 일단 DB의 내용을 home 화면에 보여주는 부분은 구현했으니, 내가 입력한 데이터를 DB에 저장하는 방법만 구현하면 된다.
template 수정하기
내용들은 html 상에 있고, 우리는 python 코드로 저장기능을 구현하고 싶으니, 일단 url을 이용해 데이터를 넘겨보자.
<form action="{% url 'create' %}">
Python
복사
URL 설정하기
path('blog/create/', blog.views.create, name="create"),
Python
복사
View 작성하기
이제 위에서 설정한 것들에 따라 create 함수를 만들어 줘야한다.
from django.shortcuts import render, get_object_or_404, redirect
from django.utils import timezone
from .models import Blog
def create(request):
blog = Blog()
blog.title = request.GET['title']
blog.body = request.GET['body']
blog.pub_date = timezone.datetime.now()
blog.save()
return redirect('/blog/' + str(blog.id))
Python
복사
create라는 함수는 blog를 불러와서 우리가 모델에 정의했던 데이터 모양대로 하나하나 넣어주는 작업이다.
•
request.GET['title']은 write.html 파일에 form태그 안에 있는 녀석이다. 코드를 확인해 보면 name="title"이라고 적혀있을텐데 그래서 GET[] 안에 'title'이 들어가는 것이다. blog.body도 동일한 논리.
•
blog.pub_date 의 경우는 입력한 시간이 자동으로 넘어가게끔 코드를 구성했다. 이때 timezone이라는 패키지를 사용해야해서 두번째 줄에 보면 import를 해주는 것이다.
•
redirect 는 요청을 처리하고 보여주는 페이지이다. render가 '요청이 들어오면 이 html 파일을 보여줘’ 라는 의미였다면, redirect는 '요청이 들어오면 저쪽 url로 보내버려’ 라는 의미를 가진다.
이제 테스트 해보자.
홈에서도 잘 보인다 ㅎㅎ
이렇게 세상에서 하나뿐인 내 블로그를 만들어보았다.