web-dev-qa-db-fra.com

comment télécharger plusieurs images dans un article de blog en django

J'essaie de permettre à chaque utilisateur de télécharger plusieurs photos sur un seul article de blog. J'essaie depuis quelques jours de trouver la meilleure façon de procéder. Quelle est la meilleure pratique pour ce faire?

D'après ce que j'ai lu, je devrais créer un modèle d'image séparé à partir du modèle de blog et utiliser une clé étrangère. Est-ce correct? Il y a ensuite la question de savoir comment leur permettre de télécharger plusieurs photos en même temps. Ai-je raison de supposer que je devrais utiliser quelque chose comme une zone de dépôt?

Tout conseil sur les meilleures pratiques de stockage des photos est également le bienvenu. J'ai regardé Amazon s3 et cloudinary. Je veux créer quelque chose qui est évolutif.

Toute aide serait très appréciée!

20
ollysmall

Vous aurez juste besoin de deux modèles. L'un pour la poste et l'autre pour les images. Votre modèle d'image aurait une clé étrangère au modèle 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')

Vous devez créer un formulaire pour chaque modèle, mais ils seront liés les uns aux autres, comme lorsque l'utilisateur remplit le formulaire, il doit également remplir le formulaire d'image pour que le message soit publié avec succès, et nous le ferons que dans les vues, mais pour l'instant votre formulaire peut ressembler à ceci

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', )

Maintenant, c'est la partie la plus importante de tout, les vues, car c'est là que le téléchargement de plusieurs images vers une seule magie se produit. Pour que nous puissions télécharger plusieurs images à la fois, nous avons besoin de plusieurs champs d'image, n'est-ce pas? C'est là que vous tombez amoureux de Django formsets . Nous allons ned Django Formsets pour y arriver, vous pouvez lire sur les Formsets) dans la documentation Django, que j'ai liée :) Mais voici à quoi devrait ressembler votre vue:

* Très important les importations

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})

Dans la vue, nous obtenons nos deux formulaires, et la vue vérifiera les deux formulaires s'ils sont valides. De cette façon, l'utilisateur doit remplir le formulaire ET télécharger toutes les images qui dans ce cas sont 3 extra=3. Ce n'est qu'alors que le message sera créé avec succès.

Votre modèle devrait alors ressembler à ceci:

<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