如何在Django后台上传多张图片到单个“选择文件”选择器中

7

我正在做一个模拟服装订购系统的小项目,以提高我的Django技能。

我需要添加几张某个物品的图片(数量不固定)。因此,在Item模型中使用固定数量的图像字段并不理想。所以,我考虑另一个模型,仅由与模型“items”通过键连接的图像组成。

现在我知道Django有内联选项,可以根据需要逐个添加模型对象。但是这似乎有点麻烦,因为您必须打开对话框并逐个选择图像。

是否可能有一个选择器,可以选择多个文件并将它们添加到模型中?


https://github.com/Chive/django-multiupload - solarissmoke
这是你的正确答案-https://dev59.com/5lsX5IYBdhLWcg3wS9w7#60961015 - Yash
也许这个答案也能帮到您。 - Muhammmed Nihad
2个回答

10
是的,有一个方便的方法。 首先声明一个图像类,例如:
class Image(models.Model):
    condo = models.ForeignKey(Condo, on_delete=models.CASCADE, related_name='images')
    image = models.FileField(upload_to="images/")
    uploaded_at = models.DateTimeField(auto_now_add=True)

在表单创建中,请不要添加用于展示文件字段的行。
class ListingForm(forms.ModelForm):
    ...
    ...
    #photos = forms.FileField(required=False) #Don't do it.

但是在模板中,除了其他行之外,也要添加这一行:
<form action="" method="post" autocomplete="off" enctype="multipart/form-data">
    {% csrf_token %}
    {{ your_form|crispy }} <br/>
    <input type="file" name="images" multiple>
    <input type="submit" value="Submit">
</form>

在处理您的 POST 请求的视图中,您可以使用以下代码处理上传的图像:

from app.forms import Image


if request.method == 'POST':
...
...
    for file in request.FILES.getlist('images'):
        instance = Image(
            condo=Condo.objects.get(your_parent_objects_id),
            image=file
        )
        instance.save()

这会为每个图像创建一个新的Image对象,并将实际文件保存到您的媒体文件夹中。

此外,我建议由于可能存在恶意行为,重命名用户上传的文件。

我通过创建一个小函数并使用它来代替"images/"部分来完成此操作。

import uuid
def images_directory_path(instance, filename):
    return '/'.join(['images', str(instance.condo_id.id), str(uuid.uuid4().hex + ".png")])

# in Image class (models.py)
image = models.FileField(upload_to=images_directory_path)

这个最后的修改会为图像生成新名称,使用uuid4,并为它们添加.png扩展名,并创建到media/文件夹的完整链接。

enter image description here

当然,上传的文件格式或大小是否有效没有验证,但这是另一个问题的话题。

您可以通过变量images访问图像,因为它是连接到给定对象(在本例中为Condo)的所有相关图像的related_name

最后,这是Vitor Freitas撰写的关于使用JavaScript插件上传多个带进度条的图片的绝佳文章


4

根据文档(https://docs.djangoproject.com/en/2.2/topics/http/file-uploads/):

上传多个文件:如果您想使用一个表单字段上传多个文件,请设置该字段小部件的多个HTML属性:

forms.py

from django import forms

class FileFieldForm(forms.Form):
    file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': 
True}))

接着,重写你的FormView子类的post方法来处理多个文件上传:

views.py

from django.views.generic.edit import FormView
from .forms import FileFieldForm

class FileFieldView(FormView):
    form_class = FileFieldForm
    template_name = 'upload.html'  # Replace with your template.
    success_url = '...'  # Replace with your URL or reverse().

    def post(self, request, *args, **kwargs):
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        files = request.FILES.getlist('file_field')
        if form.is_valid():
            for f in files:
                instance = Image(image=file)  # match the model.
                instance.save()
            return self.form_valid(form)
        else:
            return self.form_invalid(form)

并添加一个模型:

from django.db import models

class Image(models.Model):
    image = models.FileField(upload_to='images/%Y/%m/%d')
    uploaded_at = models.DateTimeField(auto_now_add=True)

并将其添加到 urls.py 的 urlpatterns 中:

path(‘upload/’,views.FileFieldView.as_view(),name=‘FileFieldView’),

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接