Python - Django를 이용한 인스타그램 클론 - 4
이전 단계에서는 글 작성 모달을 띄우는 부분 까지 완료하였다. 이제 작성한 폼이 공유하기 버튼을 누르면 새로운 피드로 추가되게 해야한다.
즉, 우리가 작성한 내용이 장고 내 DB에 들어가서 조회할 수 있도록 해야한다는 것이다.
그말인 즉슨 장고의 MTV패턴으로 설명해보자면 Template에서 받은 파일을 View에서 처리하여 Model 즉 DB 피드테이블의 데이터 타입에 맞게 저장하여야 한다는 말이다.
일반적으로 템플릿(웹)에서 데이터를 받는 방식으로 get방식도 있지만 ajax라는 방식도 있는데, ajax는 Asynchronous JavaScript and XML
의 줄임말으로써, ajax는 HTML의 반복적인 렌더를 방지한다. 즉, 기존 웹 어플리케이션에는 폼을 채우고 이를 제출하게 되면 처음 창을 띄우는 html과 제출 시 폼에 이용되는 html이 중복되는 경우가 많아서 대역폭이 낭비되는 것인데 Ajax는 이와 다르게 어플리케이션에 필요한 데이터만 요청 받을 수 있기 때문에 이러한 단점을 극복할 수 있다.여기서 동기와 비동기의 차이점을 알 수 있는데, 동기 방식에서는 db에서 html파일을 보내고 띄울 수 있을 때 까지 클라이언트는 대기를 해야하지만, ajax와 같이 비동기인 경우에는 응답을 기다리지 않고 사용자의 다른 행동을 허용한다. 우리가 쓰는 인스타그램 피드 생성은 비동기식으로 이루어진다.
우선, 피드를 구성하는 요소로 이미지, 글 내용, 글쓴이 아이디, 글쓴이 프로필 사진 네개가 있다. 피드 테이블은 좋아요 수도 포함하지만 어차피 모든 피드는 처음 생성 이후에는 좋아요 수가 0으로 정해져있으므로 피드생성으로 전달해오는 데이터로 보지 않아도 된다.
이를 구현하기 위해
우선, 공유하기 버튼에 id값을 넣어준다. 필자는 "feed_create_button" 으로 지정해주었다.그리고 이후 Jquery를 작성하는 부분에서
$('#feed_create_button').click(function(){
alert("버튼이 눌렸다");
});
이렇게 해놓고, 웹을 띄우고 공유하기를 누르면,버튼이 눌렸다고 alert가 뜰 것이다.
우리가 해야할 것은 alert가 아니라 서버호출을 해야하는 것이므로, 이를 위해서는 우리가 작성한 피드 데이터를 가져올 수 있도록 이전에 작성한 코드 중
function uploadFiles(e) {
e.stopPropagation();
e.preventDefault();
e.dataTransfer = e.originalEvent.dataTransfer; // 올린 파일을 업로드 하는
var files = e.target.files || e.dataTransfer.files;
console.log("뭔가 이미 파일을 올렸네 " + files[0].name); // 파일을 드래그 해서 여러개 올릴 수도 있기에 files내 리스트처럼 접근해야한다
if (files.length > 1) {
alert('하나만 올려라.');
return;
}
위 업로드 파일 부분에서 var files = ~ 부분이 필요하다. 즉 files라는 변수를 전역변수로 선언해주어야 한다.
그래서 jquery 작성 부분 가장 상단에
let files;
해주고 이전에 있었던 uploadFiles부분의 files는 이미 선언되었으므로 자료형 var을 없애주면 된다.
이렇게 하고 시험삼아 alert와 함께 첫 번째 file의 이름이 출력되게 해보았다
$('#feed_create_button').click(function(){
alert("공유하기를 눌렀다." + files[0].name);
});
그렇게 하고 실행하게 되면
잘 작동하는 것을 알 수 있다. 즉 우리가 올린 데이터를 받아오고 다시 출력 되었다는 것이므로 잘 받아왔다는 것을 알 수 있다.
이렇게 이미지 이름은 잘 불러왔는데, textarea부분은 어떻게 가져올까. 우선 textarea에 id값으로 'input_feed_content'를 주었다.
<textarea id="input_feed_content" style="width: 276px; height: 400px" class="form-control" id="exampleFormControlTextarea1" rows="5"></textarea>
그리고 이후 Jquery 부분에서 해당 id의 value를 가져오는 아래 코드를 삽입해 주었다.
$('#feed_create_button').click(function() {
let file = files[0];
let image = file.image;
let content = $('input_feed_content').val();
let user_id = "Jin.99";
let profile_image = "data:image/jpeg;base64,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";
// 우선 user_id와 profile_image는 우리가 html에 데이터로 불러온게 아닌 그냥 삽입해둔 상태라 다른 방식을 거치지 않고 그대로 작성해주었다.
그리고 ajax로 데이터를 저장하는 코드는 아래와 같다.
let fd = new FormData();
fd.append('file', file);
fd.append('image', image);
fd.append('content', content);
fd.append('user_id', user_id);
fd.append('profile_image', profile_image);
// form data에 데이터 추가
$.ajax({
url: "/content/upload",
data: fd,
method: "post",
processData: false,
contentType: false,
success: function(data) {
console.log("성공");
},
error: function(request, status, error){
console.log("에러");
},
complete: function(){
console.log("완료");
}
})
});
ajax는 form-data방식으로 데이터를 가져오는데, 그렇기에 new FormData() 해서 폼 데이터에 가져온 여러 데이터를 append해주었고 아래 $.ajax에서 데이터를 content/upload에 보내는 ajax코드를 썼다. 하지만 우리는 아직 contnet/upload 폴더를 만들지 않지 않았는가, 그럼에도 우선 실행해보았다. 우선 ajax는 성공 시, 에러 시, 완수 시 세 개의 콜백 함수를 둔다. processData나 contentType은 그냥 디폴트로 저렇게 둬도 되는 것 같다.
여기까지 정상적으로 했다면 아마 에러가 떠야 할 것이다.
에러라고 잘 출력한다. 404는 서버에 만들어놓은 경로가 없기에 뜨는 것이다.
이후, content의 views.py에 들어가 클래스를 하나 생성해준다. 우리가 template으로 부터 받은 데이터를 view가 DB에 넣어줘야 하므로 views에서의 작업이 필요한 것이다.
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Feed
#.은 현 폴더에서, models내 Feed 클래스를 사용한다는 것
class Main(APIView):
def get(self, request):
feed_list = Feed.objects.all().order_by('-id') #feed_list에 Feed에 있는 모든 데이터를 가져오겠다는 것
# 위 같이 Feed.objects.all()과 같은 라인이 쿼리셋 역할을 한다. 즉 sql쿼리 문에서 select * from content_feed와 같은 동작을 한다
for feed in feed_list:
print(feed.content)
return render(request, "minstagram/main.html", context=dict(feeds=feed_list)) # 딕셔너리 형태로 feed_list 데이터를 넘겨주기
class UploadFeed(APIView):
def post(self, request):
file = request.data.get('file')
image = request.data.get('image')
content = request.data.get('content')
user_id = request.data.get('user_id')
profile_image = request.data.get('profile_image')
return Response(status=200) #http response -- http:200(=success를 의미)
위 UploadFeed 클래스 처럼 template ajax에서 post로 받아온 각 파일들을 변수로 선언해준다.
그리고 urls.py에 들어가서
from django.contrib import admin
from django.urls import path
from .views import Sub
from content.views import Main, UploadFeed
urlpatterns = [
path('admin/', admin.site.urls),
path('main/', Main.as_view()),
path('content/upload', UploadFeed.as_view())
]
위와 같이 content/upload 경로를 만들어준다. (여기서 UploadFeed 클래스를 import해와야 한다).
그런데 이상하지 않은가, 우리는 이전에 DB에 파일을 올릴 때 파일 그대로 올리면 용량문제와 그에 따른 응답속도 저하 문제 등의 이유로 직접올리지 않고 이미지 파일 같은 경우는 경로를 사용해서 올리곤 했다. 그렇다면 이미지 파일들은 어디로 가야하는 것일까. 대다수 상용화된 서비스에는 이미지서버, 파일서버가 따로 존재하고 거기에 있는 파일의 주소를 DB가 참조를 한다. 장고에서는 이러한 기능으로 media를 제공하고 이 곳에 파일을 저장할 수 있도록 한다.
미디어 파일 세팅은 구글링을 해서 찾아 볼 수 있다. mychew님은 https://wayhome25.github.io/django/2017/05/10/media-file/
장고 미디어 파일 (Media Files) - 사진업로드, 파일서빙 · 초보몽키의 개발공부로그
제출된 파일, 이미지는 settings.MEDIA_ROOT 경로에 파일을 저장하고, DB 필드에는 settings.MEDIA_ROOT 내 저장된 하위 경로를 저장
wayhome25.github.io
위 블로거분의 글을 참고했다.
세팅 방법은, 아래 코드를 settings.py 가장 하단에 붙여넣는다.
# mysite/settings.py
# 각 media 파일에 대한 URL Prefix
MEDIA_URL = '/media/' # 항상 / 로 끝나도록 설정
# MEDIA_URL = 'http://static.myservice.com/media/' 다른 서버로 media 파일 복사시
# 업로드된 파일을 저장할 디렉토리 경로
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 프로젝트 경로 + 'media' 이름으로 MEDIA_ROOT라고 생성
os에서 빨간줄은 import해주면 된다.
그리고 프로젝트 폴더에 media폴더를 하나 생성해준다.
그리고 아래 코드를 urls.py에 넣어주자.
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
<urls.py>
from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from .views import Sub
from content.views import Main, UploadFeed
urlpatterns = [
path('admin/', admin.site.urls),
path('main/', Main.as_view()),
path('content/upload', UploadFeed.as_view())
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
그리고 views.py에
# 일단 파일 불러와
file = request.FILES['file']
uuid_name = uuid4().hex # 이미지에 고유한 id부여를 위해 랜덤하게 글자를 정함
save_path = os.path.join(MEDIA_ROOT, uuid_name)
with open(save_path, "wb+") as destination:
for chunk in file.chunks():
destination.write(chunk)
내용을 삽입해준다.
Upload Feed 클래스의
file = request.data.get('file')
바로 위에 넣어주면 된다.
그리고, 우리가 피드를 조회했을 때 Feed.objects.all 했던 것 처럼 Feed objects를 생성할 때는 Feed.objects.create를 쓰면 된다. 그래서 Feed를 구성하는 필드, column인 image, content 등 마다 저렇게 변수를 넣어주면 된다.
class UploadFeed(APIView):
def post(self, request):
# 일단 파일 불러와
file = request.FILES['file']
uuid_name = uuid4().hex # 이미지에 고유한 id부여를 위해 랜덤하게 글자를 정함
save_path = os.path.join(MEDIA_ROOT, uuid_name)
with open(save_path, "wb+") as destination: # with open~ 부분이 실제로 파일을 저장하는 부분, save_path에 파일을 열어 조각조각 가져와 쓴다 - 그냥 알고만 있기
for chunk in file.chunks(): # 파일변수명.chunks로 가져올 수 있다잉
destination.write(chunk)
# 이렇게 저장된 경로를 담아주기 - 이미지에
image = uuid_name
content = request.data.get('content')
user_id = request.data.get('user_id')
profile_image = request.data.get('profile_image')
Feed.objects.create(image=image, content=content, user_id=user_id, profile_image=profile_image, like_count=0)
return Response(status=200) #http response -- http:200(=success를 의미)
이렇게 하면 views.py파일은 아래와 같아 질 것이다.
import os
from uuid import uuid4
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
from Minstagram.settings import MEDIA_ROOT
from .models import Feed
#.은 현 폴더에서, models내 Feed 클래스를 사용한다는 것
class Main(APIView):
def get(self, request):
feed_list = Feed.objects.all().order_by('-id') #feed_list에 Feed에 있는 모든 데이터를 가져오겠다는 것
# 위 같이 Feed.objects.all()과 같은 라인이 쿼리셋 역할을 한다. 즉 sql쿼리 문에서 select * from content_feed와 같은 동작을 한다
for feed in feed_list:
print(feed.content)
return render(request, "minstagram/main.html", context=dict(feeds=feed_list)) # 딕셔너리 형태로 feed_list 데이터를 넘겨주기
class UploadFeed(APIView):
def post(self, request):
# 일단 파일 불러와
file = request.FILES['file']
uuid_name = uuid4().hex # 이미지에 고유한 id부여를 위해 랜덤하게 글자를 정함
save_path = os.path.join(MEDIA_ROOT, uuid_name)
with open(save_path, "wb+") as destination: # with open~ 부분이 실제로 파일을 저장하는 부분, save_path에 파일을 열어 조각조각 가져와 쓴다 - 그냥 알고만 있기
for chunk in file.chunks(): # 파일변수명.chunks로 가져올 수 있다잉
destination.write(chunk)
# 이렇게 저장된 경로를 담아주기 - 이미지에
image = uuid_name
content = request.data.get('content')
user_id = request.data.get('user_id')
profile_image = request.data.get('profile_image')
Feed.objects.create(image=image, content=content, user_id=user_id, profile_image=profile_image, like_count=0)
return Response(status=200) #http response -- http:200(=success를 의미)
이렇게 해서 실행을 해보면, 글 작성이 된다. 하지만 탑재한 이미지가 뜨지 않는데, 이미지 파일 명만 잡고 앞부분에 파일 서버 경로를 제대로 잡지 않아서이다.
그래서 main.html에서 head부분에
{% load static %}
을 넣어주고, 사진이 보여지는 곳인 {{ feed.image }} 앞에
<div><img style="width:100%; height: 100%" src="{% get_media_prefix %}{{ feed.image }}">
{% get_media_prefix %}를 추가해주면 서버 경로를 앞에 추가해 잘 뜨게 된다.
그럼 우선 이전에 만들어 놓은 피드 데이터를 모두 삭제하고, 추가해보도록 하겠다.
데이터 삭제는 그냥 데이터를 싸잡아 delete해주고 업로드하면 된다.
이렇게 하고, 공유하기
잘 올라갔다. 보우가 귀엽다. 뭐 댓글이나 이런건 html 소스코드에 추가된 부분이라 해당 부분도 수정해주면 되는 부분이다.
그리고 공유하기 버튼이 누르면 모달이 사라지지 않고 가만히 있어서 새로고침을 해야하는데, 자동으로 닫기도록 설정해주자.
ajax로 정보가 전달되는게 완료되면 location을 main으로, 즉 페이지를 새로고침 해주게 코드를 추가해주었다.
요렇게 내용을 추가하고 공유하기 누르면!
새로고침 되며 모달창이 사라지고, 피드가 조회되었다.