在 Django 中创建帖子并上传多个文件

问题描述 投票:0回答:1

我有一张动物表。对于每种动物,我都有多个图像。我希望用户能够注册一种新动物并以一种形式向其添加多个图像。截至目前,尚未创建任何记录,我不明白为什么。我已经为此苦苦挣扎了几个小时。我知道我可以通过使用表单集来实现这一点,但我更喜欢这样的东西。

我怀疑是视图造成的,但不明白为什么。

这是我不起作用的解决方案:

upl/models.py

from django.db import models 
from django.core.exceptions import ValidationError



def validate_img_extension(value):
    if not value.name.endswith(".jpg", ".jpeg", ".png"):
        raise ValidationError("Only .jpg, .jpeg og .png allowed.")

class Animal(models.Model):
    title = models.CharField(max_length=200)
    description = models.TextField(null=True, blank=True)

class AnimalImage(models.Model):
    animal = models.ForeignKey(Animal, on_delete=models.CASCADE)
    image = models.FileField(upload_to="products/", validators=[validate_img_extension])

upl/views.py

from django.shortcuts import redirect, render 
from .forms import AnimalImageForm, AnimalForm 
from .models import Animal, AnimalImage


def createAnimal(request):
    animalform = AnimalForm()
    imageform = AnimalImageForm()

    if request.method == "POST":
        animalform = AnimalForm(request.POST)
        imageform = AnimalImageForm(request.POST or None, request.FILES or None)
        images = request.FILES.getlist("image")
        if animalform.is_valid() and imageform.is_valid():
            title = animalform.cleaned_data["title"]
            describ = animalform.cleaned_data["description"]
            animal_instance = Animal.objects.create(title=title, description=describ)
            animal_instance.save()

            for i in images:
                AnimalImage.objects.create(animal=animal_instance, image=i)
            return redirect("uplhome")

    context = {"animalform": animalform, "imageform": imageform}
    return render(request, "upl/animal_form.html", context)


def uplhome(request):
    return render(request, "upl/uplhome.html")

表格.py

from django import forms
from django.forms import ClearableFileInput
from .models import Animal, AnimalImage


class MultipleFileInput(forms.ClearableFileInput):
    allow_multiple_selected = True


class AnimalForm(forms.ModelForm):

    class Meta:
        model = Animal
        fields = ["title", "description"]


class AnimalImageForm(forms.ModelForm):
    class Meta:
        model = AnimalImage
        fields = ["image"]
        widgets = {"image": MultipleFileInput()}

upl/urls.py

from django.urls import path, include 
from upl import views 
from django.conf import settings 
from django.conf.urls.static import static


urlpatterns = [
    path("uplhome", views.uplhome, name="uplhome"),
    path("createanimal", views.createAnimal, name="createanimal"), 
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

upl/animal_form.html

<h1>Animal Form </h1> 
<form class="form" method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{animalform.title.label_tag}}
{{animalform.title}}
<br><br>
{{animalform.description.label_tag}}
{{animalform.description}}
<br><br>
{{imageform.image.label_tag}}
{{imageform.image}}
<br><br>
<button type="submit">Submit</button>
</form>
<a href="{% url 'uplhome' %}">Animal Home</a>
django django-views django-forms
1个回答
0
投票

正如 Django 文档所说

如果您想使用一个表单字段上传多个文件,请创建该字段小部件的子类并将其 allow_multiple_selected 类属性设置为 True。

为了使这些文件全部通过您的表单进行验证(并使字段的值包含所有这些文件),您还必须子类化 FileField

您已经有了小部件的代码,因此只剩下 FileField 需要子类化 - 再次,来自文档的示例:

class MultipleFileField(forms.FileField):
    def __init__(self, *args, **kwargs):
        kwargs.setdefault("widget", MultipleFileInput())
        super().__init__(*args, **kwargs)

    def clean(self, data, initial=None):
        single_file_clean = super().clean
        if isinstance(data, (list, tuple)):
            result = [single_file_clean(d, initial) for d in data]
        else:
            result = [single_file_clean(data, initial)]
        return result

然后你可以在你的表单中使用这个类,如下所示:

class AnimalImageForm(forms.ModelForm):
    image = MultipleFileField()
    class Meta:
        model = AnimalImage
        fields = ["image"]

并且您必须调整验证器以允许验证多个值:

def validate_img_extension(files_list):
    for file in files_list:
        if not file.name.endswith((".jpg", ".jpeg", ".png")):
            raise ValidationError("Only .jpg, .jpeg og .png allowed.")
© www.soinside.com 2019 - 2024. All rights reserved.