CS Activity/Likelion 11th

[멋쟁이사자처럼 11기] 7회차: Static, Media, Template 상속, pagination

Jenn28 2023. 4. 3. 18:26

Static 정적 파일: 이미지, css, javascript, 등등..

-> 미리 서버에 저장 (서버에서 제공하는 파일)

-> 서버 저장 안하면 logic 일일히 돌려줘야함

 

Media 유저가 업로드 한 파일: pdf 등등..

 


 

< Static >

 

APP(blog 폴더) 내에 static 폴더 생성 -> 정적파일 넣기

 

settings.py

# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/

LANGUAGE_CODE = 'ko-kr'

TIME_ZONE = 'Asia/Seoul'

USE_I18N = True

USE_TZ = True


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

STATIC_URL = 'static/'

STATIC_ROOT = BASE_DIR / 'static'

MEDIA_URL = 'media/'

MEDIA_ROOT = BASE_DIR / 'media'

 

static 폴더 안에 - blog 폴더 - img 폴더 생성 -> 이미지 넣기

 

python manage.py collectstatic -> session에 static 폴더 또 생김

 

home.html

{% load static %} //static 불러옴

<h1>LIKELION 11 Blog Project
    <img src="{% static 'blog/img/newyorkphoto.JPG' %}" alt="이모티콘">
</h1>
<a href="{% url 'new' %}">새 글 작성하기</a>
<div>
    {% for blog in blogs %}
    <a href="{%url 'detail' blog.id %}">
        <h2>{{blog.title}}</h2>
        <p>{{blog.summary}}</p>
        <p>{{blog.created_at}}</p>
    </a>
    {% endfor %}
</div>

 

이미지파일 주소

 


 

< Media >

 

Media는 Static과 다르게 urls.py 따로 설정해줘야함

session - session의 urls.py 수정

 

urls.py

from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


# 127.0.0.1:8000/blog

 

models.py

from django.db import models

# Create your models here.
class Blog(models.Model):
    title = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)
    content = models.TextField()
    image = models.ImageField(upload_to='blog/', null=True) #이미지 안넣고 싶을 수도 있으니 null=True 추가
    
    def __str__(self):
        return self.title
    
    def summary(self):
        return self.content[:100]

 

이미지 처리 라이브러리 설치:

pip install pillow

 

models.py 수정 시 migrations 해줘야함

 

new.html -> 이미지 업로드 할 파트 필요

<h1>새 글 작성하기</h1>
<form action="{%url 'create'%}" method="POST" enctype="multipart/form-data"> //enctype 추가
    {% csrf_token %}
    제목 : <input type="text" name="title" value=""/>
    본문 : <textarea name="content" id="" cols="30" rows="10"></textarea>
    사진 : <input type="file" name="image" /> //추가
    <input type="submit" value="작성하기"/>
</form>

<a href="{% url 'home' %}">홈</a>

 

edit.html

<h1>edit 페이지</h1>

<form method="POST" action="{% url 'update' edit_blog.id %}" enctype="multipart/form-data">
    {% csrf_token %}
    <input type="text" name="title" value="{{edit_blog.title}}"/>
    <textarea name="content" id="" cols="30">{{edit_blog.content}}</textarea>
    <input type="file" name="image">
    <input type="submit" value="수정하기">
</form>

<a href="{% url 'home' %}">홈</a>
<a href="{% url 'delete' edit_blog.id %}">삭제하기</a>

 

views.py

.
.
def create(request):
    new_blog = Blog()
    new_blog.title = request.POST.get('title')
    new_blog.content = request.POST.get('content')
    new_blog.image = request.FILES.get('image')
    new_blog.save()
    return redirect('detail', new_blog.id)
.
.
def update(request, blog_id):
    old_blog = get_object_or_404(Blog, pk=blog_id)
    old_blog.title = request.POST.get("title")
    old_blog.content = request.POST.get("content")
    old_blog.image = request.FILES.get('image')
    old_blog.save()
    return redirect('detail', old_blog.id)

왜 get 함수를 쓰는가?

딕셔너리 형태에서 image라는 키가 없으면 null을 반환 (에러 안뜸, 서버 안터짐) -> 안정적

그래서 웬만해서는 get함수를 쓰는게 좋음

 

detail.html

<h1>블로그 상세 페이지</h1>
<br/>
<hr/>
<h2>{{blog.title}}</h2>
<p>{{blog.content}}</p>

{% if blog.image %}
<img src="{{blog.image.url}}" alt="이미지">
{% endif %}

<p>{{blog.created_at}}</p>

<a href="{% url 'home' %}">홈</a>
<a href="{% url 'edit' blog.id %}">수정하기</a>
<a href="{% url 'delete' blog.id %}">삭제하기</a>

 

사진 업로드 한 후 media 폴더 생김

 

글 삭제 시 media 파일 동시 삭제하는 법

https://parkhyeonchae.github.io/2020/04/13/django-project-25/

 

Django 25. 업로드(MEDIA) 파일 동시 수정 / 삭제 구현 - Today.log

2020-04-13 글 수정, 삭제시 서버단에서도 동시 처리가 되도록 하고 URL로 MEDIA파일 접근을 제한합니다. 이전 파일업로드 / 다운로드 포스팅과 이어집니다. 업로드된 파일이 있는 게시글을 삭제하거

parkhyeonchae.github.io

 


 

< Template 상속 >

 

base.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>{% block title %} {% endblock title %}</title>
</head>

<body>
    {% block content %}
    {% endblock content %}
</body>

</html>

 

home.html

{% extends "base.html" %}
{% load static %}

{% block title %}
Jenn의 블로그 홈페이지!!
{% endblock title %}

{% block content %}
<h1>LIKELION 11 Blog Project
    <img src="{% static 'blog/img/newyorkphoto.JPG' %}" alt="이모티콘" width="100">
</h1>
<a href="{% url 'new' %}">새 글 작성하기</a>
<div>
    {% for blog in blogs %}
    <a href="{%url 'detail' blog.id %}">
        <h2>{{blog.title}}</h2>
        <p>{{blog.summary}}</p>
        <p>{{blog.created_at}}</p>
    </a>
    {% endfor %}
</div>
{% endblock content %}

home.html이 base.html의 format을 바탕으로 적용됨

 


 

< Pagination >

 

Pagination: 페이지마다 일정한 수의 게시물만 보여주고 하단부에 페이지 번호로 이동이 가능하게 하는 것

 

views.py

from django.shortcuts import render,get_object_or_404,redirect
from django.core.paginator import Paginator #추가

from .models import Blog
from .forms import BlogForm


def home(request):
    blogs = Blog.objects.all()
    paginator = Paginator(blogs, 3) #페이지당 3개의 글
    page_number = request.GET.get('page') #쿼리로 보낸 page 값이 page_number에 들어감
    page_obj = paginator.get_page(page_number) #page_number에 해당하는 페이지를 가져옴
    return render(request,'home.html',{'page_obj':page_obj}) #page_obj를 home.html에 넘겨줌
.
.

 

home.html

{% extends "base.html" %}
{% load static %}

{% block title %}
Jenn의 블로그 홈페이지!!
{% endblock title %}

{% block content %}
<h1>LIKELION 11 Blog Project
    <img src="{% static 'blog/img/newyorkphoto.JPG' %}" alt="이모티콘" width="100">
</h1>
<a href="{% url 'new' %}">새 글 작성하기</a>
<div>
    {% for blog in page_obj %}
    <a href="{%url 'detail' blog.id %}" class="new-post">
        <h2>{{blog.title}}</h2>
        <p>{{blog.summary}}</p>
        <p>{{blog.created_at}}</p>
    </a>
    {% endfor %}
</div>

<span>
    {% if page_obj.has_previous %}
    <a href="?page=1">처음으로</a>
    <a href="?page={{ page_obj.previous_page_number }}">이전</a>
    {% endif %}

    <p>{{ page_obj.number }} / {{ page_obj.paginator.num_pages }}</p>

    {% if page_obj.has_next %}
    <a href="?page={{ page_obj.next_page_number }}">다음</a>
    <a href="?page={{ page_obj.paginator.num_pages }}">마지막으로</a>
    {% endif %}
</span>

{% endblock content %}

 


 

< 패키지 관리 >

 

어떤게 설치되어 있는지 txt로 만들기:

pip freeze > requirements.txt

 

내가 txt 파일을 바탕으로 다시 설치할 때:

pip install -r requirements.txt