장고로 이미지 업로드 하는 방법을 찾아보면 대부분은 모델에 이미지 필드를 추가하고 폼을 생성하여 사용자에게 사진을 받는 방식으로 진행된다. 혹시나 그 방법이 궁금해서 들어온 방문자가 있을까 해당 방법과 동시에 필자가 이번에 찾아본 필드 추가 없이 업로드를 하는 방법을 정리할 것이다.
이미지 필드로 업로드
def avatar_path(instance, filename):
return 'avatar/u/'+instance.user.username+ '/' + randstr(4) + '.' + filename.split('.')[-1]
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(blank=True, upload_to=avatar_path)
만일 사용자의 대표 아바타 이미지를 추가한다고 가정하면 위와같이 이미지 필드를 추가하고 아래와 같이 forms.py에서 업로드할 폼을 만들어 준다.
class ProfileForm(forms.ModelForm):
class Meta:
model = Profile
fields = ('avatar',)
이제 위 폼을 views.py를 통해서 사용자에게 폼을 전달해주고 파일을 받아올 것이다.
if request.method == 'POST':
if hasattr(user, 'profile'):
profile = user.profile
p_form = ProfileForm(request.POST, request.FILES, instance=profile)
else:
p_form = ProfileForm(request.POST, request.FILES)
if p_form.is_valid():
profile = p_form.save(commit=False)
profile.user = user
profile.save()
render_args['message'] = '성공적으로 변경되었습니다.'
if hasattr(user, 'profile'):
profile = user.profile
p_form = ProfileForm(instance=profile)
else:
p_form = ProfileForm()
render_args['p_form'] = p_form
뷰에서 위와같이 처리해주면 끝난다! 이미지 필드에 저장된 이미지의 경로가 들어있는 것을 확인할 수 있다.
AJAX로 이미지 업로드
단순한 이미지 업로드(AJAX)와 같은 경우 PHP를 활용해서 업로드했었다. 그러다 오늘 PHP 의존도를 낮추기 위해 해당 기능을 파이썬으로 변경하고자 하였다. 아래의 PHP코드를 Python으로 변환하였다.
<?php
include "../randstr/randstr.php";
$uploads_url = 'https://MY_DOMAIN.COM/image';
$allowed_ext = array('jpg', 'jpeg', 'png', 'gif');
$uploads_dir = '../../static/image';
$name = $_FILES['image']['name'];
$error = $_FILES['image']['error'];
$ext = strtolower(array_pop(explode('.', $name)));
if(!in_array($ext, $allowed_ext)) {
echo "허용되지 않는 확장자입니다.";
exit;
}
if( $error != UPLOAD_ERR_OK ) {
switch( $error ) {
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
echo "파일이 너무 큽니다. ($error)";
break;
case UPLOAD_ERR_NO_FILE:
echo "파일이 첨부되지 않았습니다. ($error)";
break;
default:
echo "파일이 제대로 업로드되지 않았습니다. ($error)";
}
exit;
}
$new_name = randstr(20);
if(move_uploaded_file($_FILES['image']['tmp_name'], $uploads_dir.'/'.$new_name.'.'.$ext)){
echo $uploads_url.'/'.$new_name.'.'.$ext;
} else {
echo "이미지 업로드를 실패하였습니다.";
}
?>
PHP의 경우에는 사용자에게 POST받은 순간부터 이미지 업로드가 되는 것 같다. 뭐 당연한 얘기인가… move_uploaded_file로 원하는 위치로 옮기는 것이 핵심 코드며 그 전 코드들은 예외를 처리하기 위해서 작성된 코드다.
@csrf_exempt
def image_upload(request):
if request.method == 'POST':
if request.FILES['image']:
allowed_ext = ['jpg', 'jpeg', 'png', 'gif']
image = request.FILES['image']
ext = str(request.FILES['image']).split('.')[-1].lower()
if not ext in allowed_ext:
return HttpResponse('허용된 확장자가 아닙니다.')
upload_path = 'static/image/'
file_name = randstr(20)
with open(upload_path + '/' + file_name +'.'+ ext, 'wb+') as destination:
for chunk in image.chunks():
destination.write(chunk)
return HttpResponse('https://MY_DOMAIN.COM/image/' + '/' + file_name +'.'+ ext)
else:
return HttpResponse('이미지 파일이 아닙니다.')
else:
raise Http404
파이썬의 경우에는 request.FILES를 통해서 파일이 넘어온다. 이걸 원하는 경로에 데이터 기록시켰다. PHP도 내부적으론 이와같은 일이 발생하는 거라고 추측된다. @csrf_exempt은 해당 메서드가 모델로 부터 폼을 전달받는게 아니므로 csrf 보안을 적용시킬 수가 없었기에 해당 메서드에 한해서 보안을 해제시켰다.
출처: https://baejino.com/programing/django/how-to-image-upload
'Python > Django' 카테고리의 다른 글
Django에서 blog 구현 (0) | 2020.02.19 |
---|---|
Django에 Database 사용하기 (1) | 2020.02.19 |
HTML과 python web server 구축 (0) | 2020.02.18 |
Python Socket programming (0) | 2020.02.18 |
OSI 참조 모델 이론 (0) | 2020.02.18 |