Back-end/Django

[HUFS/HUFStudy] #4 Path Converter, 글쓰기, Static/Media, 템플릿 상속, URL

성중 2021. 7. 18. 19:48

PK, Path Converter, 예외처리

 

블로그 글에 이와 같은 작업을 해줄 것이다

models.py의 Blog 클래스 안에 본문 미리보기가 100글자 까지만 보이도록 하는 함수를 작성

class Blog(models.Model):
    title = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')
    body = models.TextField()

    def __str__(self):
        return self.title # 글 제목이 타이틀로 보이도록

    def summary(self):
        return self.body[:100] # 본문 미리보기가 100글자 까지만 보이도록

home.html 파일에 함수를 넣어주면,,

{% for blog in blogs.all%}
    <h1>제목: {{blog.title}}</h1>
    <p>날짜: {{blog.pub_date}}</p>
    <p>본문 미리보기: {{blog.summary}}</p>
    <br><br>
{%endfor%}

 

100 글자씩만 나온다

이제 html 파일 상에 ‘…more’를 a링크를 달아서 넣어주고,,

{% for blog in blogs.all%}
    <h1>제목: {{blog.title}}</h1>
    <p>날짜: {{blog.pub_date}}</p>
    <p>본문 미리보기: {{blog.summary}} <a href="{% url %}">...more</a></p>
    <br><br>
{%endfor%}

이제 a링크를 클릭했을 때, 본문 전체를 보여주는 detail.html 파일로 이동하게 해보자

 

detail.html 페이지를 하나만 만들어 내용만 교체할 것이다
구현할 기능 (PK: 데이터 구분자 / Path Converter: URL 계층 디자인 / 예외처리: 404 에러)
views.py에 detail 함수를 정의하고, Path Converter를 달아준 url을 먼저 생성할 것이다
blog_id 는 detail 함수에 넘겨주는 인자로 blog의 몇 번째 객체를 가져올지 명시한다
객체의 특정 번호 역할을 하는 것이 pk(primary key)이고 이를 활용해 코드를 넣어주면..

views.py

from django.shortcuts import get_object_or_404, render
from .models import Blog

def home(request):
    blogs = Blog.objects #쿼리셋 -> 모델의 Blog 객체 목록을 변수에 저장
    return render(request, 'home.html', {'blogs': blogs})

def detail(request, blog_id):
    blog_detail = get_object_or_404(Blog, pk= blog_id) #이용자가 원한 몇 번 블로그 객체

    return render(request, 'detail.html', {'blog':blog_detail})

home.html에서 id 정보와 함께 링크를 연결!

    <p>본문 미리보기: {{blog.summary}} <a href="{%url 'detail' blog.id%}">...more</a></p>

detail.html 내용을 구성

<h1>자세한 본문 내용입니다.</h1>
<br><br>
<h1>제목: {{blog.title}}</h1>
<p>날짜: {{blog.pub_date}}</p>
<p>자세한 본문: {{blog.body}}</p>

 

detail.html이 잘 작동한다!

시간 템플릿 태그 표기

 

[Django]Date와 Time을 나타내는 template filter

모델에 따라서 날짜와 시간을 필드로 필요로 하는 경우가 많이 존재합니다. 이럴 경우, DateField 나 DateTimeField 를 사용하여 값을 저장합니다. 하지만 이럴 경우에 데이터는 기본적으로 July 4, 2019, 9

ssungkang.tistory.com

글쓰기 페이지 만들기

Bootstrap으로 블로그를 조금 다듬었다

글을 입력하기 위해 일일이 admin 페이지에 들어가지 말고 글쓰기 페이지를 만들어보자

 

HTML의 form 태그에 입력한 내용을 바로 데이터 베이스에 저장하려면,,
Views.py에는 html을 띄우는 함수와 form의 내용을 DB에 등록하는 함수가 필요하다!

new.html을 생성해서 urls.py, views.py에 연동하고 대략적인 form을 구성했다

        <div style="margin: 2rem;">
            <form action="">
                <h3>제목:</h3>
                <input type="text" name="title">
                <br><br>
                <h3>본문:</h3>
                <textarea cols="40" rows="10" name="body"></textarea>
                <br><br>
                <input class="btn btn-dark" type="submit" value="제출하기">
            </form>
        </div>

views.py에서 새로운 함수를 활용할 것이기 때문에 action을 create라는 임의의 url로 보내자

            <form action="{% url 'create' %}">

urls.py에 임의의 해당 url을 생성하자 (html을 띄우는 것이 아니라 함수를 실행하기 위한 url)

    path('blog/create/',blog.views.create, name="create"),

views.py에 form의 글을 DB로 보내는 create 함수를 만들어주자

def create(request): #new.html의 form에서 입력받은 내용을 DB로 넣어주는 함수
    blog = Blog()
    blog.title = request.GET['title']
    blog.body = request.GET['body']
    blog.pub_date = timezone.datetime.now()
    blog.save() #객체에 해당하는 내용들을 /admin 에 저장
    return redirect('/blog/'+str(blog.id)) #글 작성을 완료하면 해당 글 detail이 뜨도록

redirect() 함수를 활용하면 바로 해당 url로 이동한다

 

Static 다루기

블로그에 포트폴리오 탭을 추가하면서 정적 파일에 대해 알아보자

 

Static: 미리 서버에 저장된 그대로 서비스해주는 파일
Dynamic: 언제, 누가, 어디서, 어떻게 요청하는지에 따라 받는 데이터가 달라질 수 있음

Static으로 미리 준비해둔 사진을 띄우고 Media를 통해 사진을 업로드해보자

 

Static 파일들을 담을 폴더를 만들고 어디로 모을지 지정해야 한다
구체적으로는 이렇다

새로운 Portfolio 앱을 만들고 settings.py에 등록, views에 등록, urls.py에 import 후 링크를 생성했다

 

portfolio.html 레이아웃은 Bootstrap Examples를 긁어왔다

portfolio 앱 내부에 static 폴더를 만들고 settings.py에서 파일을 모으도록 지정해줘야 한다

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'portfolio', 'static')
] # static 파일들이 현재 어디에 있는지

STATIC_ROOT = os.path.join(BASE_DIR, 'static') 
# static 파일들이 어디로 모일 것인지

settings.py 하단에 이렇게 써주고,,

 

manage.py가 속한 상위 폴더의 bash에 해당 명령어를 입력해준다
상위 static 폴더가 생성될 것이다

static 파일을 사용할 html 파일 최상단에 템플릿 태그를 넣어주자

{% load static %}
<!doctype html>

이제 html 상에 img 태그와 템플릿 태그로 static 파일을 넣어주면 된다!

           <img src="{% static '티벳토끼.jpg' %}" width="100%" height="225" alt="비스카차">

Media 다루기

settings.py에서 업로드 될 파일(Media)을 저장할 디렉토리 경로와 URL을 지정해줘야 한다

 

설정의 차이를 알아보자 !
대략적인 순서

settings.py 하단에 이렇게 추가해주자

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.2/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'portfolio', 'static')
] # static 파일들이 현재 어디에 있는지

STATIC_ROOT = os.path.join(BASE_DIR, 'static') 
# static 파일들이 어디로 모일 것인지

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

MEDIA_URL = '/media/'

이제 urls.py에서 두가지 import를 해주고 path를 추가해주면 되는데,,

from django.conf import settings
from django.conf.urls.static import static

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

url을 타고 온 파일을 DB에 넣어주는 작업을 해주자

 

models.py에 데이터를 받아줄 형식을 Class로 정의하고,,

class Portfolio(media,Model):
    title = models.CharField(max_length=255)
    image = models.ImageField(upload_to='images/')
    description = models.CharField(max_length=500)

    def __str__(self):
        return self.title

이미지를 DB에 넣으려면 bash에 pip 하나를 더 설치해줘야 한다

 

manage.py 가 있는 bash에 ‘python -m pip install Pillow’를 입력해 설치
이후 DB에 연결해주는 명령어들을 차례대로 입력

이후 admin.py에도 연동해준다

 

from django.contrib import admin
from .models import Portfolio

admin.site.register(Portfolio)

이제 views.py에서 DB의 Portfolio 데이터를 출력하도록 함수를 수정하자!

from django.shortcuts import render
from .models import Portfolio

def portfolio(request):
    portfolios = Portfolio.objects
    return render(request, 'portfolio.html', {'portfolios':portfolios})

쿼리셋과 all 메소드, 템플릿 태그로 HTML 상에 띄우는 작업을 해주자

        {%for portfolio in portfolios.all %}
        <div class="col">
          <div class="card shadow-sm">
            <img src="{{portfolio.image.url}}" width="100%" height="225">

            <div class="card-body">
              <p class="card-text">{{portfolio.description}}</p>
              <div class="d-flex justify-content-between align-items-center">
                <div class="btn-group">
                  <button type="button" class="btn btn-sm btn-outline-secondary">View</button>
                  <button type="button" class="btn btn-sm btn-outline-secondary">Edit</button>
                </div>
                <small class="text-muted">9 mins</small>
              </div>
            </div>
          </div>
        </div>
        {%endfor%}

반복할 부분을 잡아주고 내용도 탬플릿 변수로 수정해준다

 

이제 /admin에서 데이터를 추가히면 사이트에 차례대로 띄워진다

 

템플릿 상속

Navbar 처럼 HTML 상에서 계속 겹치는 내용을 여러 번 복붙하지 말고 상속시키자
대략적인 순서
‘ 프로젝트 폴더’에 templates 폴더를 만들고 그 안에 base.html을 만들어준다

settings.py의 TEMPLATES 탭의 ‘DIRS’에 프로젝트 폴더와 templates 폴더를 써주자

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['secondproject/templates'],

이제 base.html에 공통적인 부분을 넣어주고

 

내용을 넣을 부분에 해당 코드를 넣어준다

        <!--여기에 컨텐츠-->
        {% block contents %}
        
        {% endblock %}
        <!--여기에 컨텐츠-->

이후 다른 html 파일들은 base.html 파일로 보낸 내용을 삭제하고, base.html을 불러오는 코드를 넣어준다

{% extends 'base.html' %}

{% block contents %}
<body>
  <div>
    <!--안겹치는 부분-->
    <div style="margin: 1.5rem;">
      <br>
      <h2>{{blog.title}}</h2>
      <p>{{blog.pub_date}}</p>
      <p>{{blog.body}}</p>
   </div>
   <!--안겹치는 부분-->
  </div>
</body>
{% endblock %}

URL 관리

대규모 프로젝트에서 앱이 추가/삭제되거나 다른 프로젝트에서 앱을 활용할 수도 있는데,,

 

이렇게 App별로 URL을 관리해줄 필요가 있다!

예를 들어 blog/… url들을 관리하려면 해당 App 안에 urls.py 파일을 생성해준다

from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('<int:blog_id>', views.detail, name="detail"),
    path('new/', views.new, name="new"),
    path('create/', views.create, name="create"),  
]

이런 식으로 간략하게 코드를 받아온다

 

원래 urls.py에는 include를 import해주고 옮겨간 url들은 삭제해준다

from django.urls import path, include

대신 urlpatterns에 이렇게 넣어준다

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', blog.views.home, name="home"),
    path('blog/', include('blog.urls')), # App의 urls.py에 옮겨간 url들
    path('portfolio/', portfolio.views.portfolio, name="portfolio"),
]

이렇게 폴더별로 url들을 관리할 수 있게 되었다!

 

본 내용은 멋쟁이사자처럼의 '9기 운영진 교육'을 바탕으로 작성되었습니다.