Django

Django 실습(4) Model과 DB를 이용한 게시물 관리와 업로드

UserDonghu 2023. 10. 11. 19:22

간단하게 startapp blog 만 하고 이미지를 업로드한 게시물들의 목록과 검색 기능을 구현한 index와 게시물의 상세 정보를 볼 수 있는 post와 게시글을 작성하고 파일을 업로드 하는 write를 구현해보자.


실습

여태 했던 실습 내용을 참고하여 여기까지 만들어서 runserver 했을 때 http://127.0.0.1:8000/blog, http://127.0.0.1:8000/blog/write, http://127.0.0.1:8000/blog/1 이 다 잘 실행되는지 확인.

 

 

blog / models.py 에 DB 설계하기

 

아래 사이트를 참고

 

 

https://docs.djangoproject.com/en/4.2/ref/models/fields/ 

 

Django

The web framework for perfectionists with deadlines.

docs.djangoproject.com

 

이미지를 저장할거기 때문에 이미지 관련 라이브러리인 pillow 설치

pip install pillow

 

models.py 수정

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100) # 제목
    contents = models.TextField() # 내용
    main_image = models.ImageField(blank=True, null=True) # 이미지. blank=True : 이 필드는 필수가 아니다. null=True : 그 이전 게시물이 비어있어도 된다.
    created_at = models.DateTimeField(auto_now_add=True) # 생성시간. auto_now_add=True : 지금 시간을 자동으로 넣는다.
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self): # 출력했을때 밖으로 보이는 것
        return self.title

 

models.py 수정 후 입력

python manage.py makemigrations : DB를 조작할 수 있는 코드

python manage.py migrate : 실제 DB에 반영

 

blog / admin.py 수정

# blog / admin.py
from django.contrib import admin
from .models import Post

admin.site.register(Post)

 

python manage.py createsuperuser 로 admin계정 생성

 

이미지가 실제로 저장될 폴더 설정하기

settings.py 에 맨 마지막 줄에 추가

MEDIA_ROOT = BASE_DIR / 'media'
MEDIA_URL = '/media/'

 

 

admin페이지에서 로그인 후, 게시물 작성해보기

127.0.0.1:8000/admin
admin로그인 후 Posts 들어오기
게시물 작성해보기

게시물을 작성해보면 사진 파일이 blog / media / 사진.jpg 경로에 저장된것을 볼 수 있다.

 

이미지 url 연결하기.

tutorialdjango / urls.py 수정

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('blog/', include('blog.urls')),
]

urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) # 이미지 경로로 연결되는 url링크 추가

Main image 사진 이름 클릭

admin페이지에서 게시물에 첨부된 사진을 클릭하면 이미지 경로로 된 url이 연결된다.

이미지가 나옴

templates / blog 에 부모 html 인 menu.html 생성

<h2>My Blog</h2>
<a href="{% url 'blog:index' %}">Main</a>
<a href="{% url 'blog:write' %}">Write</a>
{% block content %}
{% endblock %}

 

상속받는 html 파일들을 수정

 

blog / index.html

{% extends 'blog/menu.html' %}

{% block content %}
<h1>블로그 글 목록</h1>
<!-- input값을 get을 사용해서 ?q=검색할내용 으로 보냄 -->
<form action="" method="get">
    <input name="q" type="search">
    <button type="submit">검색</button>
</form>
<ul>
    {% for i in db %}
    <p><a href="{% url 'blog:post' i.id%}">{{i.title}}</a></p>
    <p>{{i.created_at}}</p>
    {% endfor %}
</ul>
{% endblock %}

 

blog / post.html

{% extends 'blog/menu.html' %}

{% block content %}
<h1>{{db.title}}</h1>
<p>{{db.contents}}</p>
<p>{{db.updated_at}}</p>
{% if db.main_image %}
<!-- db.main_image.url : image의 경로 -->
<img src="{{db.main_image.url}}">
{% endif %}
{% endblock %}

 

blog / write.html

{% extends 'blog/menu.html' %}

{% block content %}
<!--  post방식으로 form을 보내고, image를 보내려면 enctype을 꼭 적어야한다. -->
<form action="" method="post" enctype="multipart/form-data">
	<!-- post방식으로 보낼때 csrf_token 꼭 적어야함 -->
    {% csrf_token %}
    <label for="title">제목</label>
    <input id="title" name="title" type="text">
    <label for="contents">내용</label>
    <textarea id="contents" name="contents"></textarea>
    <input type="file" name="image">
    <button type="submit">저장</button>
</form>
{% endblock %}

 

 

blog / views.py 수정하기

views.py 수정

from django.shortcuts import render
from .models import Post
from django.db.models import Q

def index(request):
    if request.GET.get('q'): # index.html에서 검색한 q의 값
        q = request.GET.get('q')
        # 데이터베이스를 연결해주는 ORM 코드
        db = Post.objects.filter(Q(title__icontains=q) | Q(contents__icontains=q)).distinct()
        # Post에서 title 또는 contents에 q를 대소문자 구분 없이 포함하는 것들을 중복을 제거해서 db로 하겠다.
    else:
        db = Post.objects.all() # q가 없으면 그냥 Post의 모든 요소를 db로
    context = {'db': db}
    return render(request, 'blog/index.html', context)

def write(request):
    if request.method == 'POST': # POST 일때는 이렇게 처리
        title = request.POST.get('title')
        contents = request.POST.get('contents')
        image = request.FILES.get('image')
        if title and contents and image: # image가 있을 때
            newpost = Post.objects.create(title=f'{title}', contents=f'{contents}', main_image=image)
            newpost.save()
        elif title and contents: # image가 없을 때
            newpost = Post.objects.create(title=f'{title}', contents=f'{contents}')
            newpost.save()
        return index(request) # index로 넘어감
    else: # POST 요청이 아닐때는 그냥 페이지 보여줌
        return render(request, 'blog/write.html')

def post(request, pk):
    db = Post.objects.get(pk=pk) # Post의 요소들중 pk가 pk인것을 db로
    context = {'db': db}
    return render(request, 'blog/post.html', context)

 

결과

blog main
아리를 검색했을 때
blog/write

write에서 글을 쓰고 파일을 올리면 DB에 추가된다.

blog 글 post

 

blog 글 post