장고 - Multi image upload 학습

  • 이번 포스트에서는 한번에 여러 이미지들을 업로드하는 방법에 대해 학습해볼 것이다.

ex) yanolja_project

1. 모델 작성

  • 경로 : stay(앱) > models.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from django.db import models
    from django.contrib.auth.models import get_user_model
    from django.template.defaultfilters import slugify

    class Stay(models.Model):
    name = models.CharField(max_length=50)
    username = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name="stays")
    ...

    def get_image_filename(instance, filename):
    name = instance.stay.name
    slug = slugify(name)
    return "stay_images/%s-%s" % (slug, filename)

    class Image(models.Model):
    stay = models.ForeignKey(Stay, on_delete=models.CASCADE, related_name="images_stay")
    image = models.ImageField(upload_to=get_image_filename, verbose_name="Image")

    def __str__(self):
    return self.stay.name + "image"

2. 폼 작성

  • 경로 : stay > forms.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    from django import forms

    from .models import *


    class StayForm(forms.ModelForm):
    class Meta:
    model = Stay
    fields = ('name', 'location', 'introduce', ...)

    def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.fields['name'].label = '상호명'
    self.fields['location'].label = '위치'
    self.fields['introduce'].label = '숙소 소개'
    ...

    class ImageForm(forms.ModelForm):
    image = forms.ImageField(label='')
    class Meta:
    model = Image
    fields = ('image',)

3. 뷰 작성(객체 생성 시, 이미지 멀티 업로드)

  • 경로 : stay > views.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    from django.shortcuts import render, redirect
    from django.forms import modelformset_factory
    from django.contrib.auth.decorators import login_required
    from django.urls import reverse
    from .forms import *

    @login_required
    def stay_create(request):
    # modelformset_factory 함수 사용(extra로 최대 업로드할 수 있는 이미지 개수 설정)
    ImageFormSet = modelformset_factory(Image, form=ImageForm, extra=3)

    if request.method == "POST":
    stay_form = StayForm(request.POST, request.FILES)
    formset = ImageFormSet(request.POST, request.FILES, queryset=Image.objects.none())
    # form validation
    if stay_form.is_valid() and formset.is_valid():
    stay_form = stay_form.save(commit=False)
    stay_form.username = request.user
    stay_form.save()
    for form in formset.cleaned_data:
    # 유저가 모든 이미지들을 업로드하지 않았을 경우 crash 방지
    if form:
    image = form['image']
    photo = Image(stay=stay_form, image=image)
    photo.save()
    # urls.py에서 app_name이 stay이고, name이 stay_list인 url로 이동
    return redirect(reverse("stay:stay_list"))
    else:
    print(stay_form.errors, formset.errors)
    else:
    # method가 POST가 아닌 경우, 즉 처음 stay_create url로 이동한 경우
    stay_form = StayForm()
    formset = ImageFormSet(queryset=Image.objects.none())


    return render(request, 'stay/stay_create.html', {'stay_form':stay_form, 'formset':formset})

4. 커스텀 템플릿 작성

  • 경로 : stay > templates > stay > stay_create.html
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {% block content %}
    <div>
    <form id="stay_form" method="post" action="" enctype="multipart/form-data">
    {% csrf_token %}
    {{ stay_form.as_p }}
    {{ formset.management_form }}
    {% for form in formset %}
    {{ form }}
    {% endfor %}
    <div style="height:30px;"></div>
    <input type="submit" name="submit" value="upload" />
    </form>
    </div>
    {% endblock %}