https://pypi.org/project/django-imagekit/
pip install PIL or pip install Pillowpip install django-imagekit프로젝트.settings.py > INSTALLED_APP 에 
imagekit 추가어플.models.pypython manage.py makemigrations 를 해도 No changes detected가 뜨게됨from django.db import models
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFill
# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    image = models.ImageField(blank=True)
    # source = 뭐를 기준으로 만들지 - imageField 변수명이 들어감
    # processors - 작업내용
    ## ResizeToFill = 리사이징된 크기 정해주기
    # format - 확장자
    # quality - 해상도
    image_thumbnail = ImageSpecField(source='image',
                                      processors=[ResizeToFill(200, 200)], 
                                      format='JPEG',
                                      options={'quality': 60})
    created_at = models.DateTimeField(auto_now_add=True)
리사이징 된 사이즈를 HTML에 사용하기
<img src="{{ post.image_thumbnail.url }}" class="card-img-top" alt="{{ post.image }}">리사이징 된 사진 찾아보기
데이터베이스에 보면 리사이징된 이미지에 대한 정보는 따로 데이터베이스에 저장되지 않음
media 폴더 > CACHE > images > 사진명 폴더에 따로 저장되어있음
어플.models.py 
from django.db import models
from imagekit.models import ProcessedImageField
from imagekit.processors import ResizeToFill
# Create your models here.
class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    # upload_to : 어느폴더에 올릴지 선택
    ## media 폴더 안에 upload_to 에 준 이름 폴더에 리사이징된 사진이 저장되게 됨
    image = ProcessedImageField(upload_to='image_thumb',
                                           processors=[ResizeToFill(100, 50)],
                                           format='JPEG',
                                           options={'quality': 60})
    created_at = models.DateTimeField(auto_now_add=True)
데이터 베이스에 적용하기
python manage.py makemigrationspython manage.py migrate 어플.models.py 에서 바꿔주기
%Y/%m/%d/를 넣어 연/월/일 을 붙여서 폴더가 생성되게 함image = ProcessedImageField(upload_to='images/%Y/%m/%d/',
                                            processors=[ResizeToFill(100, 50)],
                                            format='JPEG',
                                            options={'quality': 60})
글쓰는 페이지와 글 수정페이지는 거의 대부분의 코드가 동일하다
그래서 페이지를 나눠서 관리하는 것 비효율적이다.
그러기 위해서 request 객체가 어떤 것을 통과하고, 어떤 요소를 가지고 있는지
어플.form.html 
request.resolver_match.url_name 는 현재 들어온 주소랑 매칭시키는 역할url_name : URL과 일치하는 URL 패턴의 이름route : 일치하는 URL 패턴의 경로app_name : URL 과 일치하는 URL 패턴의 애플리케이션 네임 스페이스namespace : URL과 일치하는 URL 패턴의 인스턴스 네임 스페이스{% extends 'base.html' %}
{% load bootstrap5 %}
{% block content %}
  {% if request.resolver_match.url_name == 'create' %}
    <div class="fs-3 text-center bg-info p-3">create</div>
  {% else %}
    <div class="fs-3 text-center bg-warning p-3">update</div>
  {% endif %}
  <form action="" method="POST" enctype="multipart/form-data">
    {% csrf_token %}
    {% bootstrap_form form %}
    <input class="btn btn-primary" type="submit">
  </form>
{% endblock content %}
어플.views.py 
create 함수부분의 render 페이지를 바꿔줌return render(request, 'posts/form.html', context)update 함수부분의 render 페이지를 바꿔줌return render(request, 'posts/form.html', context)https://docs.djangoproject.com/ko/3.1/intro/tutorial03/#a-shortcut-get-object-or-404
어플.views.py
post = get_object_or_404(Post, pk=pk) Http404 발생from django.shortcuts import get_object_or_404
def detail(request, pk):
    # post = Post.objects.get(pk=pk) 이것을 밑에 것으로 바꿈
    post = get_object_or_404(Post, pk=pk)
    context = {
        'post': post,
    }
    return render(request, 'posts/detail.html', context)