如何在 django 中将多张图片上传到博客文章

Posted

技术标签:

【中文标题】如何在 django 中将多张图片上传到博客文章【英文标题】:how to upload multiple images to a blog post in django 【发布时间】:2016-03-04 14:01:17 【问题描述】:

我试图允许每个用户将多张图片上传到单个博客文章。几天来,我一直在尝试找出最好的方法来做到这一点。这样做的最佳做法是什么?

根据我的阅读,我应该从博客文章模型中创建一个单独的图像模型并使用外键。那正确吗? 然后是如何让他们同时上传多张图片的问题。我假设我应该使用 drop zone 之类的东西是对的吗?

也欢迎任何有关存储照片的最佳做法的建议。我看过 Amazon s3 和 cloudinary。我想创建一些可扩展的东西。

任何帮助将不胜感激!

【问题讨论】:

添加多个图像上传koensblog.eu/blog/7/multiple-file-upload-django 或其他方式的一种方法是使用 django-ckeditor 并使用其图像上传插件之一,其中图像上传到您的 amazon s3 存储并且仅插入 img 标签使用您的 s3 图像位置的正确地址进入您的内容 【参考方案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 表单集来实现这一点,您可以在 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
from .models import Images

@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()
            # use django messages framework
            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>

【讨论】:

非常感谢!您如何将像 dropzone js 这样的拖放系统合并到其中?如果您想要拖放方法,是否需要表单集? @ollysmall 抱歉,我帮不了你,我不知道 javascript,所以我不能告诉你你会怎么做。但是检查一下github.com/sigurdga/django-jquery-file-upload 我试图完全按照你的要求做,我发现 django jquery 文件上传,但我不知道如何使用它并让它与表单集一起使用。试试看吧? @qasimalbaqali 我参加聚会要迟到了,但我在my question 这里有一个稍微不同的问题。希望你能帮我解决它 管理员应该是什么样子? @bgarcial 抱歉,我有一段时间没有接触 django,对此我无能为力。但也许这会有所帮助***.com/a/38739423/4708186【参考方案2】:

逐步解决方案 => 甚至,我也被卡住了。所以这就是我成功的做法。

Finally实现下面的代码,我实现了

1 个带有许多图像的笔记模型 多次上传同时,带有相同的“选择文件”按钮,并像在 Gmail 文件上传中一样保存在一起强>)

这是我的笔记和图像模型-(或see full code)

class Note(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
    title = models.CharField(max_length=30)
    text = models.TextField(null=True,blank=True)
    created_date = models.DateTimeField(auto_now_add=True)
    last_modified = models.DateTimeField(auto_now=True)

class Images(models.Model):
    note = models.ForeignKey(Note,on_delete=models.CASCADE)
    image = models.ImageField(upload_to=user_directory_path,null=True,blank=True)

这是我的表单(Link of doc. on multiple upload)-(或see full code)

class NoteForm(forms.ModelForm):
    class Meta:
        model = Note
        fields = ['title','text'] #make sure to mention field here, if nothing is mentioned then all will be required.

class NoteFullForm(NoteForm): #extending form
    images = forms.FileField(widget=forms.ClearableFileInput(attrs='multiple': True))

    class Meta(NoteForm.Meta):
        fields = NoteForm.Meta.fields + ['images',]

这是我的视图文件-(或see full code)

def addNoteView(request):
if request.method == "POST":
    #images will be in request.FILES
    form = NoteFullForm(request.POST or None, request.FILES or None)
    files = request.FILES.getlist('images')
    if form.is_valid():
        user = request.user
        title = form.cleaned_data['title']
        text = form.cleaned_data['text']
        note_obj = Note.objects.create(user=user,title=title,text=text) #create will create as well as save too in db.
        for f in files:
            Images.objects.create(note=note_obj,image=f)
    else:
        print("Form invalid")

并且,最后我的 Html 文件 (be sure to bind files as said in docs)-(或 see full code)

<form action="% url 'note:add_note' %" method="post" class="note-form" enctype="multipart/form-data">% csrf_token %
  <div class="form-group">
    <label for="note-title">Title</label>
    <input type="text" name="title" class="form-control" id="note-title" placeholder="Enter Title" required>
  </div>
  <div class="form-group">
    <label for="note-description">Description</label>
    <textarea type="text" name="text" class="form-control" id="note-description" placeholder="Description here"></textarea>
  </div>
  <div class="form-group">
    <label for="note-image">Images</label>
    <input type="file" name="images" class="form-control-file" id="note-image" multiple>
  </div>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

【讨论】:

【参考方案3】:

答案很简单。不需要这么多代码。

HTML 文件

<input type="file" name = "files" multiple />

VIEWS.PY

files = request.FILES.getlist('files')

for f in files:
    a = Image(image=f)
    a.save()

【讨论】:

【参考方案4】:

我遇到了类似的问题。在我的模型中,一篇文章必须有一个缩略图(图像),然后我为可选图像设置了另外五个字段。问题出现在应用安全过滤器后,图像源不会呈现,因为它不再是 HTML,

&lt;img src="article.image1.url" class="some class"&gt;

行不通。我使用的一个临时解决方案是根据文章的标题命名图像。如果我在写“django 过滤器”,我会将我的附加图像命名为 djangofiltersimage1.png 或 djangofiltersimage2.png,这很有帮助,因为在我的模型中,每篇文章都有一个唯一的标题。然后我将图像源更改为:

&lt;img src="/media/djangofiltersimage1.png" class="some class"&gt;

唯一的问题是图像的严格命名。您可以通过为博客图像创建模型来上传更多图像。与此同时,我仍在寻找另一种解决方案。 你可以看看我的博客here

【讨论】:

【参考方案5】:

getlist 名称和 html 输入名称字段应该相同

models.py

class studentImage(models.Model):
        image = models.ImageField(upload_to='media/')
    
        def __str__(self):
            return self.image

views.py

def studentImageView(request):
    if request.method == "POST":
        images = request.FILES.getlist('images')
        for image in images:
            photo = studentImage.objects.create(image=image,)
            photo.save()

    return render(request, 'image.html')

用于模板

<form method="post" enctype="multipart/form-data" >
  % csrf_token %
   <input required name="images" type="file" multiple >
  <button class="btn btn-primary" type="submit">Upload</button>
</form>

【讨论】:

以上是关于如何在 django 中将多张图片上传到博客文章的主要内容,如果未能解决你的问题,请参考以下文章

如何在 django 中将图像添加到帖子中

thinkphp如何将多张上传的图片根据状态分别存储!

django 格式的多张图片,带有多重上传

如何将多张图片上传到 sanity.io?

LayUI上传图片(文件)的时候,上传多张图片(文件)会调用多次接口,而我们想要让上传多个文件的时候只调用一次接口,怎么解决?

LayUI上传图片(文件)的时候,上传多张图片(文件)会调用多次接口,而我们想要让上传多个文件的时候只调用一次接口,怎么解决?