django Form에서 이미지를 업로드해서 DB에 저장하는 기능을 구현하는 방법이다.
이미지 파일이 form에서 view로 넘어가지도 않는 문제, view에서 조회하는 문제들을 해결하였다.
1. media폴더 경로 설정
- 프로젝트 폴더 settings.py 마지막줄에 MEDIA_URL, MEDIA_ROOT 추가
# setting.py
# ... 이외의 기본 세팅들
MEDIA_ROOT = BASE_DIR/'media'
MEDIA_URL = '/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, include
from user.views import index
# 이미지를 업로드하자
from django.conf.urls.static import static
from django.conf import settings
urlpatterns = [
... url conf ...
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
2. 모델 설계
제품 테이블을 만들고 거기에 이미지파일을 같이 저장하려고 모델을 만들었다.
ImageField를 사용하여 Image필드를 만들었다.
upload_to 옵션은 사용하지 않았기 때문에 프로젝트 폴더내의 media경로에 바로 이미지파일이 저장된다.
# models.py
class Product(models.Model):
product = models.CharField(max_length=32,verbose_name='product_name')
price = models.IntegerField(verbose_name='product_price')
description = models.TextField(verbose_name='product_description')
image = models.ImageField(blank=True, null=True, verbose_name='product_image')
stock = models.IntegerField(verbose_name='product_stock')
register_date = models.DateTimeField(auto_now_add=True, verbose_name='product_register_date')
def __str__(self):
return self.product
class Meta:
db_table = 'product_table'
verbose_name = '제품'
verbose_name_plural = '제품'
- (선택) models.py에서 models.ImageField()에 upload_to옵션 추가. upload_to옵션은 위의 1번에서 지정된 media경로 내에서 다시 어느 경로로 저장할지 설정하는 옵션이다.
- "cannot use ImageField because Pillow is not installed."라는 오류메세지가 뜰 경우
이미지처리를 위해서는 django의 추가 패키지가 필요한데 Pillow라는 라이브러리를 사용하는 가상환경에 설치해주면 된다.
pip install Pillow 로 끝!
3. 폼(Form) 설계
forms.ImageField()를 이용하여 폼을 구성한다.
# forms.py
class RegisterForm(forms.Form):
image = forms.ImageField(
error_messages={
'required':'사진을 첨부해주세요'
},
label='image')
4. 뷰(View) 설계
함수형 뷰 또는 클래스 뷰 모두 똑같이 적용할 수 있다고 한다. 나는 클래스 뷰를 이용해서 만들어보았다.
폼 유효성검사 후 작업을 하기 위해서 form_valid함수를 오버라이딩했다.
form_valid함수는 form을 인자로 받는다.
form.cleaned_data로 폼에 입력된 값들을 가져올 수 있다.
form.cleaned_data는 딕셔너리 형태라서 key값을 조회해서 값을 가져올 수 있다.
난 처음에 form.data로 값을 조회했었는데 이때는 이미지파일을 불러오지 못해서 한동안 해맸었다.
data 속성에는 csrf토큰 값이 들어있는데 이상하게 이미지 파일은 저장이 되지 않았다. 이유는 잘 모르겠다..
여튼 form.data속성이 아닌 form.cleaned_data속성에서 폼에 입력한 값에 접근하여 사용하면 된다.
# views.py
class ProductRegister(FormView):
template_name = 'product_register.html'
form_class = RegisterForm
success_url = '/product/list'
def form_valid(self, form):
product = Product(
product = form.cleaned_data.get('product'),
price = form.cleaned_data.get('price'),
description = form.cleaned_data.get('description'),
stock = form.cleaned_data.get('stock'),
image = form.cleaned_data.get('image')
)
product.save()
return super().form_valid(form)
5. html 템플릿 설계
form테그에 input테그를 넣어준뒤 submit으로 제출하면 된다.
이때 form 테그내에 enctype="multipart/form-data" 을 설정해주어야 한다.
그럼 입력한 이미지 값이 잘 넘어간다.
# product_register.html
<form method="POST" action="." enctype="multipart/form-data" style="user-select: auto;">
{% csrf_token %}
{% for field in form %}
<div class="form-group">
<lable for="{{ field.id_for_label }}">{{ field.label }}</lable>
{% if field.name == 'description' %}
<textarea class="form-control" name="{{ field.name }}" id="field.id_for_label" placeholder="상품설명을 써주세요~!"></textarea>
{% else %}
<input type="{{ field.field.widget.input_type }}" class="form-control" id="{{ field.id_for_label }}" placeholder="{{ field.label }}" name="{{ field.name }}" />
{% endif %}
</div>
{% if field.errors %}
<span style="color:red">{{ field.errors }}</span>
{% endif %}
{% endfor %}
<button type="submit" class="btn btn-primary">상품등록</button>
참고한 사이트
https://roseline124.github.io/django/2019/03/27/pickmeal-media.html
https://docs.djangoproject.com/en/3.0/topics/forms/
https://kgu0724.tistory.com/117
'파이썬 python > django' 카테고리의 다른 글
[django] Related Field got invalid lookup: icontains 오류 (0) | 2022.06.17 |
---|---|
[django] User모델 커스터마이징 할 때 오류 (0) | 2022.06.14 |
[django] 프로젝트 배포 시 sqlite3 버전 오류 (0) | 2022.05.02 |
[django] django.db.utils.OperationalError: table already exist (0) | 2022.04.26 |
[django] no such table: auth_user (0) | 2022.03.24 |