web-dev-qa-db-ja.com

djangoで複数の画像をブログ投稿にアップロードする方法

各ユーザーが複数の写真を単一のブログ投稿にアップロードできるようにしています。私は数日前からこれを行うための最良の方法を考え出しています。これを行うためのベストプラクティスは何ですか?

私が読んだものから、ブログ投稿モデルから別の画像モデルを作成し、外部キーを使用する必要があります。そうですか?次に、複数の写真を同時にアップロードできるようにする方法の問題があります。ドロップゾーンのようなものを使うべきだと思い込んでいますか?

写真を保存するためのベストプラクティスに関するアドバイスも歓迎します。 Amazon s3とcloudinaryを見てきました。スケーラブルなものを作りたい。

どんな助けも大歓迎です!

20
ollysmall

必要なのは2つのモデルだけです。 1つは投稿用で、もう1つは画像用です。画像モデルには、Postモデルへの外部キーがあります。

from Django.db import models
from Django.contrib.auth.models import User
from Django.template.defaultfilters import slugify

class Post(models.Model):
    user = models.ForeignKey(User)
    title = models.CharField(max_length=128)
    body = models.CharField(max_length=400)

def get_image_filename(instance, filename):
    title = instance.post.title
    slug = slugify(title)
    return "post_images/%s-%s" % (slug, filename)  


class Images(models.Model):
    post = models.ForeignKey(Post, default=None)
    image = models.ImageField(upload_to=get_image_filename,
                              verbose_name='Image')

モデルごとにフォームを作成する必要がありますが、ユーザーはフォームポストに記入するとき、ユーザーがポストを正常にポストするために画像フォームも完成させる必要があるため、相互に関連します。ビューではそれが、今のところあなたのフォームは次のように見えることができます

from Django import forms
from .models import Post, Images

class PostForm(forms.ModelForm):
    title = forms.CharField(max_length=128)
    body = forms.CharField(max_length=245, label="Item Description.")

    class Meta:
        model = Post
        fields = ('title', 'body', )


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

これは、ビューのすべての最も重要な部分です。これは、単一のマジックに複数の画像をアップロードする場所であるためです。複数の画像を一度にアップロードできるようにするには、複数の画像フィールドが必要ですか?そこであなたはDjango formsets に恋をします。これを実現するためにDjango formsets Djangoドキュメンテーション、私がリンクしました:)しかし、これはあなたのビューがどのように見えるべきであるかです:

*非常に重要な輸入品

from Django.shortcuts import render
from Django.forms import modelformset_factory
from Django.contrib.auth.decorators import login_required
from Django.contrib import messages
from Django.http import HttpResponseRedirect
from .forms import ImageForm, PostForm

@login_required
def post(request):

    ImageFormSet = modelformset_factory(Images,
                                        form=ImageForm, extra=3)
    #'extra' means the number of photos that you can upload   ^
    if request.method == 'POST':

        postForm = PostForm(request.POST)
        formset = ImageFormSet(request.POST, request.FILES,
                               queryset=Images.objects.none())


        if postForm.is_valid() and formset.is_valid():
            post_form = postForm.save(commit=False)
            post_form.user = request.user
            post_form.save()

            for form in formset.cleaned_data:
                #this helps to not crash if the user   
                #do not upload all the photos
                if form:
                    image = form['image']
                    photo = Images(post=post_form, image=image)
                    photo.save()
            messages.success(request,
                             "Yeeew, check it out on the home page!")
            return HttpResponseRedirect("/")
        else:
            print(postForm.errors, formset.errors)
    else:
        postForm = PostForm()
        formset = ImageFormSet(queryset=Images.objects.none())
    return render(request, 'index.html',
                  {'postForm': postForm, 'formset': formset})

ビューでは、両方のフォームを取得しており、ビューは両方のフォームが有効かどうかを確認します。そのようにして、ユーザーはフォームに記入し、この場合3 extra=3。そうして初めて、投稿が正常に作成されます。

テンプレートは次のようになります。

<form id="post_form" method="post" action="" enctype="multipart/form-data">

    {% csrf_token %}
    {% for hidden in postForm.hidden_fields %}
        {{ hidden }}
    {% endfor %}

    {% for field in postForm %}
        {{ field }} <br />
    {% endfor %}

    {{ formset.management_form }}
    {% for form in formset %}
        {{ form }}
    {% endfor %}


    <input type="submit" name="submit" value="Submit" />
</form>
36
qasimalbaqali