[멋쟁이사자처럼 11기] 7회차: Static, Media, Template 상속, pagination
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 파일 동시 삭제하는 법
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