如何在Django CreateView中创建多图上传功能?

3
我有一个Django项目,我在这个项目中创建了一个“post”操作,以便用户能够分享多张图片的帖子。但是我遇到了一个问题。我无法编写多张图片上传功能。我查看了很多内容,但都没有起作用。要么它会报告问题,要么上下文未发送到我想要的HTML页面。请帮帮我。我想要的多张图片功能应该在CreateView下,并应放置在同一模板中。此外,应该有4个图像上传按钮,最后一个按钮应分配多个特性(给HTML标记)。
models.py:
class Photo(models.Model):
    post= models.ForeignKey(Person, on_delete=models.CASCADE)

    image = models.ImageField(upload_to=get_image_filename)
    uploaded_at = models.DateTimeField(auto_now_add=True)

views.py:

class PersonCreateView(CreateView):
    model = Person
    form_class = PersonForm
    success_url = reverse_lazy('person_changelist')

forms.py:

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


class PersonForm(forms.ModelForm):
    title = forms.CharField(max_length=128)
    body = forms.CharField(max_length=245, label="Item Description.")
    file_field = forms.FileField(widget=forms.ClearableFileInput(attrs={'multiple': True}))

    class Meta:
        model = Person
        widgets = {
            'valyuta': forms.RadioSelect,
            'barter': forms.CheckboxInput,
            
        }
        fields = ('country', 'city', 'ban', 'yurus', 'reng', 'qiymet', 'valyuta', 'yanacaqnovu', 'oturucu', 'squtu', 'buraxilisili', 'hecm', 'seher', 'barter', 'metin')

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['city'].queryset = City.objects.none()


        if 'country' in self.data:
            try:
                country_id = int(self.data.get('country'))
                self.fields['city'].queryset = City.objects.filter(country_id=country_id).order_by('name')
            except (ValueError, TypeError):
                pass  # invalid input from the client; ignore and fallback to empty City queryset
        elif self.instance.pk:
            self.fields['city'].queryset = self.instance.country.city_set.order_by('name')

所以你想要的是:用户可以上传多张自己的照片,而你希望在单个表单中接受这些多个图像? - BATMAN
我的意思是,说点什么。我正在尝试制作一个广告网站,所以当用户进入帖子创建选项卡时,我想在多图上传区域(在同一链接中)与需要填写的文本字段(使用我创建的文本字段类或其他内容)相遇。我正在CreateView中编写函数,但没有发生任何事情。请问你能帮我吗? - Vusal Heyderli
你应该研究一下formsets的工作原理,以使其正常运行。https://docs.djangoproject.com/en/3.0/topics/forms/formsets/#formsets - BATMAN
我想要的并不太复杂。我只是想在views.py中的PersonCreateView(CreateView)下放置一个函数,该函数还需加载多个图像,并且必须放置在与CreateView相同的链接中(success_url = reverse_lazy('person_changelist'))。 - Vusal Heyderli
我已经通过覆盖CreateView的post方法实现了多图上传。如果您仍然感兴趣,我可以回答您的问题。 - Conor
显示剩余2条评论
3个回答

1
我曾经也遇到同样的问题,但最终我成功了。因此我想分享我的解决方案。 首先我们需要创建两个模型,其中一个用于放置ImageField,并使用ForeignKey与第一个模型连接。

models.py

class Item(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="items")
    name = models.CharField(max_length=100)


class ItemImage(models.Model):
    item = models.ForeignKey(Item, on_delete=models.CASCADE)
    img = models.ImageField(default="store/default_noitem.jpg", upload_to=get_image_dir)

然后使用inlineformset_factory创建表单。特别适用于通过外键处理相关对象的情况。

forms.py

from django import forms
from django.forms.models import inlineformset_factory

from .models import Item, ItemImage

class  ItemImageForm(forms.ModelForm):
    class Meta:
        model = ItemImage
        exclude = ()

class ItemForm(forms.ModelForm):
    class Meta:
        model = Item
        fields = ["name",]

ItemImageFormSet = inlineformset_factory(
    Item, ItemImage, form=ItemImageForm,
    fields=['img'], extra=3, can_delete=True  # <- place where you can enter the nr of img
)

最后。

views.py

class ItemCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    template_name = "items/add_item_form.html"
    success_message = 'Item successfully added!'
    form_class = ItemForm

    def get_context_data(self, **kwargs):
        data = super(ItemCreateView, self).get_context_data(**kwargs)
        data['form_images'] = ItemImageFormSet()
        if self.request.POST:
            data['form_images'] = ItemImageFormSet(self.request.POST, self.request.FILES)
        else:
            data['form_images'] = ItemImageFormSet()
        return data

    def form_valid(self, form):
        context = self.get_context_data()
        form_img = context['form_images']
        with transaction.atomic():
            form.instance.user = self.request.user
            self.object = form.save()
            if form_img.is_valid():
                form_img.instance = self.object
                form_img.save()
        return super(ItemCreateView, self).form_valid(form)

记得在表单集中添加(self.request.POST, self.request.FILES),并且在包含<form>标签的 HTML 中添加enctype="multipart/form-data"


0

不使用PhotoForm类和inlineformset_factory的方法。

models.py

class Photo(models.Model):
    post= models.ForeignKey(
        Person, on_delete=models.CASCADE, related_name="person_images"
    )
    image = models.ImageField(upload_to=get_image_filename)
    uploaded_at = models.DateTimeField(auto_now_add=True)

views.py

class PersonCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    form_class = PersonForm
    template_name = "pages/add_person.html"
    success_url = reverse_lazy("person_changelist")
    success_message = _("Person created successfully!")

    def form_valid(self, form):
        form.instance.user = self.request.user
        person_data = form.save()

        # Save the images of person.
        with transaction.atomic():
            images = self.request.FILES.getlist("images")
            for image in images:
                form.instance.person_images.create(post=person_data, image=image)
        return super().form_valid(form)

0

看看这是否有效。 创建一个简单的HTML表单,而不是Django的模型表单

<form enctype="multipart/form-data" action="" method="post">
    <input type="file" name="uploaded_images" accept="image/*" multiple>
    <input type="submit" name="upload" value="Upload">
</form>

在您看来:

if request.method == 'POST':
    for afile in request.FILES.getlist('uploaded_images'):
        #Save images in respective models with the links to other models
        return redirect('back/to/same/url')

这将使用户能够一次上传多个图像,您将能够轻松地处理单个图像。


1
他正在谈论使用CreateView(基于类的视图),这是一个基于函数的视图的代码。 - Conor
同意,看着我两年前的回答,感觉我创造了更多的混乱而不是解决方案。希望他已经解决了他的问题。 - BATMAN

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