在Django中把Base64字符串保存为ImageField

在数据model中使用ImageField来管理avatar。

python 复制代码
class User(models.Model):
    AVATAR_COLORS = (
        ('#212736', 'Black'),
        ('#2161FD', 'Blue'),
        ('#36B37E', 'Green'),
        ('#F5121D', 'Red'),
        ('#FE802F', 'Orange'),
        ('#9254DE', 'Purple'),
        ('#EB2F96', 'Magenta'),
    )

    def generate_filename(self, filename):
        url = "avatar-{}-{}".format(self.user.username, filename)
        return url
    avatar = models.ImageField(upload_to=generate_filename, verbose_name='头像', null=True, blank=True)
    avatar_color = models.CharField(verbose_name='头像颜色', choices=AVATAR_COLORS, max_length=10, blank=True, null=True)
    #这里省略其他字段

前端avatar字段传输的是Base64字符串,Django后端将其转换为ContentFile后进行save。

首先,确保你已经安装了Pillow库,它是Django中处理图像的常用库。

python 复制代码
import base64
import binascii
import imghdr
import io
import uuid

from django.core.exceptions import ValidationError
from django.core.files.base import ContentFile


class Base64ToImageFile(object):
    """
    A django-rest-framework field for handling image-uploads through raw post data.
    It uses base64 for en-/decoding the contents of the file.
    """
    ALLOWED_TYPES = (
        "jpeg",
        "jpg",
        "png",
        "gif"
    )
    EMPTY_VALUES = (None, '', [], (), {})
    INVALID_FILE_MESSAGE = "Please upload a valid image."
    INVALID_TYPE_MESSAGE = "The type of the image couldn't be determined."

    def to_file(self, base64_data):
        # Check if this is a base64 string
        if base64_data in self.EMPTY_VALUES:
            return None
        if isinstance(base64_data, str):
            # Strip base64 header.
            if ';base64,' in base64_data:
                header, base64_data = base64_data.split(';base64,')

            # Try to decode the file. Return validation error if it fails.
            try:
                decoded_file = base64.b64decode(base64_data)
            except (TypeError, binascii.Error, ValueError):
                raise ValidationError(self.INVALID_FILE_MESSAGE)
            # Generate file name:
            file_name = self.get_file_name(decoded_file)
            # Get the file name extension:
            file_extension = self.get_file_extension(file_name, decoded_file)
            if file_extension not in self.ALLOWED_TYPES:
                raise ValidationError(self.INVALID_TYPE_MESSAGE)
            complete_file_name = file_name + "." + file_extension
            data = ContentFile(decoded_file, name=complete_file_name)
            return data
        raise ValidationError('Invalid type. This is not an base64 string: {}'.format(
            type(base64_data)))

    def get_file_name(self, decoded_file):
        return str(uuid.uuid4())

    def get_file_extension(self, filename, decoded_file):
        try:
            from PIL import Image
        except ImportError:
            raise ImportError("Pillow is not installed.")
        extension = imghdr.what(filename, decoded_file)

        # Try with PIL as fallback if format not detected due
        # to bug in imghdr https://bugs.python.org/issue16512
        if extension is None:
            try:
                image = Image.open(io.BytesIO(decoded_file))
            except (OSError, IOError):
                raise ValidationError(self.INVALID_FILE_MESSAGE)

            extension = image.format.lower()

        extension = "jpg" if extension == "jpeg" else extension
        return extension


def base64_string_to_file(base64_string):
    return Base64ToImageFile().to_file(base64_string)

在创建用户过程中,给avatar字段赋值ContentFile类型

python 复制代码
        avatar_file = base64_string_to_file(avatar_string)
        if avatar_file:
            request_data["avatar"] = avatar_file
        else:
            request_data.pop('avatar', None)
        serializer = UserCreateSerializer(data=request_data)
        if serializer.is_valid():
            user = serializer.save()
相关推荐
山峰哥7 分钟前
造价算量系统SQL优化,慢查询从9秒压到35毫秒‌
大数据·数据库·sql·编辑器·深度优先
AC赳赳老秦19 分钟前
电力能源公开数据采集实操:用 OpenClaw 合规抓取电网电价与发电量数据,生成区域能源供需分析报告
大数据·数据库·人工智能·python·php·deepseek·openclaw
Discipline~Hai1 小时前
Linux网络编程05-sqlite3数据库
linux·c语言·网络·数据库·sqlite·linux应用软件编程
青禾8371 小时前
一文入门 MySQL + MongoDB + Redis:三大数据库核心知识
数据库·mysql·mongodb
努力努力再努力wz1 小时前
【Redis入门系列】:从 RESP 协议到 redis-plus-plus:Redis 客户端编程与 C++ 接口设计
开发语言·数据库·c++·redis·分布式·缓存·架构
志栋智能1 小时前
凌晨3点的告警,如何用AI在5分钟内完成定界?
运维·服务器·数据库·人工智能·自动化
G.E.M.小白1 小时前
【SQLite3 数据库】从安装、SQL 操作到 C/C++ API 实战
数据库·oracle·sqlite3
神明不懂浪漫1 小时前
【第一章】MySQL简介
数据库·经验分享·笔记·mysql·oracle
山岚的运维笔记2 小时前
mysql 专业笔记 -- 第 14 章:GROUP BY
运维·数据库·笔记·后端·学习·mysql·dba
zcn1262 小时前
不同列or运算优化经验
数据库·sql优化改写