如何在django中上传图片而不使用django表单

pdkcd3nj  于 2023-03-13  发布在  Go
关注(0)|答案(2)|浏览(164)

型号

class Property(models.Model):
    property_id = models.BigAutoField(primary_key=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    status = models.CharField(max_length=30, default='Public')
    title = models.CharField(max_length=30, default='')
    image1 = models.ImageField(upload_to="properties/images", default='', null=True)
    image2 = models.ImageField(upload_to="properties/images", default='', null=True)

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

        if self.image1:
           img1 = Image.open(self.image1.path)
           if img1.height > 1500 or img1.width > 1500:
              output_size = (1500, 1500)
              img1.thumbnail(output_size)
              img1.save(self.image1.path)
    
       if self.image2:
           img2 = Image.open(self.image2.path)
           if img2.height > 1500 or img2.width > 1500:
              output_size = (1500, 1500)
              img2.thumbnail(output_size)
              img2.save(self.image2.path)

在此模型中,我将图像加载到image 1和image 2中。我使用PIL创建缩略图

查看

def post(self, request):
    status = request.POST.get('status')
    title = request.POST.get('title')
    image1 = request.FILES.get('image-1')
    image2 = request.FILES.get('image-2')

    if Property.objects.all():
        pid = Property.objects.all().last().property_id + 1
    else:
        pid = 0

    Property(property_id = pid, author = request.user, status = status, title = title).save()

    p = Property.objects.all().filter(property_id = pid)[0]

    if image1:
        p.image1 = image1
    
    if image2:
        p.image2 = image2

    p.save()

    return redirect('add_item')

超文本标记语言

<form method="POST" class="row gx-3 gy-4">
    {% csrf_token %}
    <!-- Status -->
    <label for="inputStatus">Status</label>
    <select name="status" id="inputStatus" required>
        <option disabled selected>Choose an option</option>
        {% for status in all_status %}
            <option value="Public">{{status}}</option>
         {% endfor %}
    </select>
    <!-- Title -->
    <label for="inputTitle">Title</label>
    <input name="title" type="text" required>
    <!-- Images -->
    <label for="inputTitle">Images</label>
    <input name="image-1" type="file">
    <input name="image-2" type="file">
</form>

有了这个代码,我可以添加Product_id,author,status,但是image 1和image 2没有上传到属性/图像,当我在django-admin中打开这个模型时,它看起来像一个空白的图像字段

mfuanj7w

mfuanj7w1#

如果您提交文件,则需要指定如何使用enctype="multipart/form-data" attribute [mozilla-dev]

<form method="POST" class="row gx-3 gy-4" enctype="multipart/form-data">
    {% csrf_token %}
    <!-- … -->
</form>
p5fdfcr1

p5fdfcr12#

通常用Django保存文件而不使用Django表单看起来是很扭曲的。不过,这里有一个简单的步骤来说明这个过程应该是怎样的:
您首先有了HTML表单:

<form method="POST" class="row gx-3 gy-4">
    {% csrf_token %}
    <!-- Status -->
    <label for="inputStatus">Status</label>
    <select name="status" id="inputStatus" required>
        <option disabled selected>Choose an option</option>
        {% for status in all_status %}
            <option value="Public">{{status}}</option>
        {% endfor %}
    </select>
    <!-- Title -->
    <label for="inputTitle">Title</label>
    <input name="title" id="idTitle" type="text" required>
    <!-- Images -->
    <label for="inputTitle">Images</label>
    <input name="image-1" id="idImage1" type="file">
    <input name="image-2" id="idImage2" type="file">
    <input type="submit" id="submit_btn" class="btn btn-success center_btn" value="Save Data">
</form>

在指定HTML结构之后,是时候深入研究Javascript了:
但是等等......有两种方法可以发送数据:
1.准确使用FileReader对象的readAsArrayBuffer方法
1.仅使用formData对象(我们将在下面使用)

**注意:**最好使用Form元素的formData对象将数据发送到服务器,因为它已经为您处理了与文件有关的所有内容

// selecting the input elements in JS 
const idImage1 = document.getElementById("idImage1")
const idImage2 = document.getElementById("idImage2")
const idTitle = document.getElementById("idTitle")
const submit_btn = document.getElementById("submit_btn")
// Selecting the csrf token from a django form
const csrftoken_elmt = document.querySelector('[name=csrfmiddlewaretoken]'); 

// Preparing the function that will send the data
const sendData = async (data, link) => {
    try {
        // ${baseURL}registration/enregistrement_pro/
        let response = await fetch(`${link}`, 
            {
                method: 'POST', 
                body: data, 
                headers: {
                    // 'Content-Type': 'multipart/form-data', 
                    'X-CSRFToken': csrftoken_elmt.value,
                }, 
            }
        );
        return await response.json();
    } catch(err) {
        console.error(err);
    }
}

// Building the submit button code:
submit_btn.addEventListener("click", (evt) => {
    evt.preventDefault();
    
    const formData = new FormData()

    formData.append("title", idTitle.value);
    formData.append("Image1", idImage1.files[0]);
    formData.append("Image2", idImage2.files[0]);

    // Using the data-sending method declared above to send the data to the server
    sendData(formData, 'Your Link to you view.py')
    .then (json => {
        // Place codes After the response from the server here
        console.log("The Json: ", json)
    })
})

接下来,我们在服务器端处理请求,django:

def post(self, request):
    title = request.POST.get('title')
    image1 = request.FILES.get('Image1')
    image2 = request.FILES.get('Image2')

    if Property.objects.all():
        pid = Property.objects.all().last().property_id + 1
    else:
        pid = 0

    Property(property_id = pid, author = request.user, status = status, title = title).save()

    p = Property.objects.all().filter(property_id = pid)[0]

    if image1:
        p.image1 = image1

    if image2:
        p.image2 = image2

    p.save()

    return redirect('add_item')

这样就可以确保文件确实被上传。
还有许多其他文章可以帮助您进一步了解如何使此过程更好:
How do i receive image file in django view from fetch post without using django forms
Sending data to server using javascript file streaming object without using formData
Further reading from this Django doc article: File Uploads

相关问题