通过 .update() ORM 更新 Django ImageField

Posted

技术标签:

【中文标题】通过 .update() ORM 更新 Django ImageField【英文标题】:Update Django ImageField through .update() ORM 【发布时间】:2021-10-22 04:57:01 【问题描述】:

此处已提出类似问题:

Update ImageField without forms in django,和 Django ImageField is not updating when update() method is used

但答案始终是相同的(“改用.save()”)-此解决方案确实有效,但由于模型上的信号我无法控制,我想了解是否有任何替代方法可以使用。

# serializers.py

from drf_extra_fields.fields import Base64ImageField
from rest_framework import serializers


class ProfileSerializer(serializers.Serializer):
    email = serializers.CharField(required=False, allow_null=True)
    image = Base64ImageField(required=False, allow_null=True, max_length=None, use_url=True)

# views.py

def get_as_base64(url: AnyStr):
    if url is None:
        return None, None
    full_name = url.split("/")[-1]
    my_base = base64.b64encode(requests.get(url).content)
    return my_base, full_name

def do_profile_update(profile: Dict):
    b64_image, file_name = get_as_base64(profile.get("url"))
    if b64_image and file_name:
        *_, file_ext = file_name.split(".")
        b64_image = f"data:image/file_ext;base64,b64_image.decode('utf-8')"

    build_dict = 
        "email": profile.get("email"),
        "image": b64_image,
    
    serializer = ProfileSerializer(data=build_dict)
    serializer.is_valid()  # returns True
    # serializer.validated_data = 'email': 'test@example.org', 'image': <SimpleUploadedFile: 11735acf-6d96-4c62-9e6a-8ebb7f7ea509.jpg (image/jpeg)>
    Profile.objects.filter(pk=pk).update(**serializer.validated_data)  # This saves the *name* of the image to the database, but no image file

我了解 ImageField 基本上是 CharField,我可以在数据库中看到图像的名称,但图像没有写入服务器。

我的问题归结为:有没有办法单独将图像写入服务器,检索新保存图像的路径,并在.update()中使用?

TYIA。

【问题讨论】:

是否可以选择使用保存并以某种方式禁用信号? 不是真的,因为信号上有几个装饰器,即使我断开信号连接,它们似乎总是在运行 【参考方案1】:

您可以使用 django 的 DefaultStorage 类将文件单独保存到媒体服务器(请参阅 docs)。

import os
import io
import requests
from django.conf import settings
from django.core.files.images import ImageFile
from django.core.files.storage import default_storage

response = requests.get(url)
full_name = url.split("/")[-1]
img_path = os.path.join(settings.MEDIA_ROOT, full_name)
image = ImageFile(io.BytesIO(response.content))
default_storage.save(img_path, image)

【讨论】:

我在哪里/如何运行.update(),我应该更新什么 - imageimg_path 问题是,我真的不知道 Base64ImageField 的作用。在我看来,它只是将 base64 图像作为字符串保存在数据库中,实际上并没有将其写入磁盘。该 base64 字符串足以在前端呈现您的图像。您的问题是如何将文件上传到服务器。如果它是一个常规的 ImageField,你会用 full_name 更新它,因为 django 已经知道 MEDIA_ROOT 在哪里。

以上是关于通过 .update() ORM 更新 Django ImageField的主要内容,如果未能解决你的问题,请参考以下文章

Django as ORM - 异步执行更新查询而不阻塞

Django之ORM

Django ORM中使用update_or_create功能

Django ORM 操作

Android ORM -- Litepal

Kohana MVC 框架 ORM 模式强制更新数据库