python/Django

[Django] 파일 다운로드

http://portfolio.wonpaper.net 2022. 5. 6. 19:57

위의 이미지를 보면 업로드된 파일들은 모두 media 폴더내에 별도로 files 와 images 폴더로 각각 별도로 저장되어 있다.

 

[ /config/settings.py ] - 프로젝트앱에서 /media 폴더 설정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pathlib import Path
import os
 
BASE_DIR = Path(__file__).resolve().parent.parent
 
LANGUAGE_CODE = 'ko-kr'
 
TIME_ZONE = 'Asia/Seoul'
 
USE_I18N = True
 
USE_TZ = True
 
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]
 
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
cs

 

[ /config/urls.py ] 

 

1
2
3
4
5
6
7
8
9
10
11
from django.contrib import admin
from django.urls import path
from django.conf.urls import include
from django.conf.urls.static import static
from django.conf import settings
 
urlpatterns = [
    path('admin/', admin.site.urls),
    path('member/', include('member.urls')),
    path('board/', include('board.urls')),
+ static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
cs

11번 라인에서 MEDIA_ROOT 설정한다.

 

[ /board/models.py ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from django.db import models
from member.models import Member
 
 
class Board(models.Model):
    no = models.AutoField(db_column='no', primary_key=True)
    member_no = models.ForeignKey(Member, db_column='member_no', on_delete=models.SET_NULL, null=True)
    subject = models.CharField(db_column='subject', max_length=255)
    content = models.TextField(db_column='content', blank=True)
    read_num = models.IntegerField(db_column='read_num', default=0)
    reg_date = models.DateTimeField(db_column='reg_date', auto_now_add=True)
    update_date = models.DateTimeField(db_column='update_date', auto_now_add=True)
 
    image1 = models.ImageField(db_column='image1', max_length=255, blank=True)
    upfile1 = models.FileField(db_column='upfile1', max_length=255, blank=True)
 
    class Meta:
        db_table = 'board'
 
    def __str__(self):
        return '제목: ' + self.subject + ', 이름: ' + self.member_no.name
cs

위에서 image1 과 upfile1 부분이 업로드 파일 아이템들이다.

 

 

[ /board/view.py ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from django.shortcuts import render, redirect
from django.core.files.storage import FileSystemStorage
from django.conf import settings
from django.http import HttpResponse
from .models import Board
from member.models import Member
import datetime, os, random
 
def file_download(request):
    path = request.GET['path']
    file_path = os.path.join(settings.MEDIA_ROOT, path)
 
    if os.path.exists(file_path):
        binary_file = open(file_path, 'rb')
        response = HttpResponse(binary_file.read(), content_type="application/octet-stream; charset=utf-8")
        response['Content-Disposition'= 'attachment; filename=' + os.path.basename(file_path)
        return response
    else:
        message = '알 수 없는 오류가 발행하였습니다.'
        return HttpResponse("<script>alert('"+ message +"');history.back()'</script>")
cs

실제 다운로드 처리 부분이다. path 경로로 GET 방식으로 파일 정보를 받는다.

 

[ /board/urls.py ]

 

1
2
3
4
5
6
7
8
9
10
11
from django.urls import path
from . import views
 
urlpatterns = [
    path('', views.board_list, name='index'),
    path('list/', views.board_list, name='board_list'),
    path('detail/<int:no>/', views.board_detail, name='board_detail'),
    path('write/', views.board_write, name='board_write'),
    path('download/', views.file_download, name='file_download'),
    path('update/<int:no>/', views.board_update, name='board_update'),
]
cs

9라인이 파일다운로드 URL 형식이다.

 

실제 게시판 뷰 상세페이지에서 다운로드 관련 소스를 클릭하면 파일 다운로드가 완료된다.

 

 

[ /templates/board/board_detail.html ]

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<tr>
    <td>이미지파일</td>
    <td>
{% if board.image1 %}
    <a href="/board/download?path=board/images/{{ board.image1 }}">{{ board.image1 }}</a>
{% endif %}
    </td>
    <td>첨부파일</td>
    <td>
{% if board.upfile1 %}
    <a href="/board/download?path=board/files/{{ board.upfile1 }}">{{ board.upfile1 }}</a>
{% endif %}
    </td>
</tr>
cs