[Django 0-1] Core.Files

Core.Files 模块

Django 的核心模块之一,封装文件操作,提供对文件的上传、下载、删除、查看大小等功能。

提供的功能

  1. 存储后端解耦,支持多种存储后端,使得在不同存储后端中的文件数据都能以相同的方式操作
  2. 文件上传、下载、删除、查看大小等功能

支持的文件存储后端

  • FileSystemStorage:基于本地文件系统的存储后端,适用于开发环境和小型项目。
  • MemoryStorage:基于内存的存储后端,适用于开发环境,小型项目,处理一些临时文件。
第三方存储后端库
  • django-storages:支持 S3, LibCloud, Azure, DigitalOcean, Google Cloud Storage, Backblaze B2, SFTP, FTP, Dropbox, Oracle Cloud 等云存储服务。
  • django-oss-storage: 支持阿里云 OSS 对象存储服务, 可能已经失效但仍可以 fork 修改。
  • django-qiniu-storage: 支持七牛云对象存储服务, 可能已经失效但仍可以 fork 修改。

支持的文件类型

  • File:普通文件,可以是任何类型的文件,如图片、视频、文档等。
  • ImageFile:图片文件,继承自 File,提供图片处理的功能,也没什么功能就多了,height,width 两个方法,需要安装 Pillow 库。
  • UploadedFile: 抽象类,提供文件上传的基本功能,主要是满足 form-data 上传的文件。
  • TemporaryUploadedFile(继承自 UploadedFile): 存放在临时文件中
  • InMemoryUploadedFile(继承自 UploadedFile): 存储在内存中

可以学习的地方

  1. 自定义文件存储后端
python 复制代码
class Storage:
    # 文件存储后端无关的接口,可以提供默认实现
    def open(self, name, mode="rb"): ...

    def save(self, name, content, max_length=None): ...

    def get_valid_name(self, name): ...

    def get_alternative_name(self, file_root, file_ext): ...

    def get_available_name(self, name, max_length=None): ...

    def generate_filename(self, filename): ...

    def path(self, name): ...

    # 与文件存储后端相关的接口,需要子类实现
    def _open(self, name, mode="rb"):
        raise NotImplementedError(
            "subclasses of Storage must provide an _open() method"
        )

    def delete(self, name):
        """
        Delete the specified file from the storage system.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a delete() method"
        )

    def exists(self, name):
        """
        Return True if a file referenced by the given name already exists in the
        storage system, or False if the name is available for a new file.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide an exists() method"
        )

    def listdir(self, path):
        """
        List the contents of the specified path. Return a 2-tuple of lists:
        the first item being directories, the second item being files.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a listdir() method"
        )

    def size(self, name):
        """
        Return the total size, in bytes, of the file specified by name.
        """
        raise NotImplementedError("subclasses of Storage must provide a size() method")

    def url(self, name):
        """
        Return an absolute URL where the file's contents can be accessed
        directly by a web browser.
        """
        raise NotImplementedError("subclasses of Storage must provide a url() method")

    def get_accessed_time(self, name):
        """
        Return the last accessed time (as a datetime) of the file specified by
        name. The datetime will be timezone-aware if USE_TZ=True.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a get_accessed_time() method"
        )

    def get_created_time(self, name):
        """
        Return the creation time (as a datetime) of the file specified by name.
        The datetime will be timezone-aware if USE_TZ=True.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a get_created_time() method"
        )

    def get_modified_time(self, name):
        """
        Return the last modified time (as a datetime) of the file specified by
        name. The datetime will be timezone-aware if USE_TZ=True.
        """
        raise NotImplementedError(
            "subclasses of Storage must provide a get_modified_time() method"
        )
  1. 文件读写锁
python 复制代码
def _fd(f):
    """Get a filedescriptor from something which could be a file or an fd."""
    return f.fileno() if hasattr(f, "fileno") else f


if os.name == "nt":
    import msvcrt
    from ctypes import (
        POINTER,
        Structure,
        Union,
        WinDLL,
        byref,
        c_int64,
        c_ulong,
        c_void_p,
        sizeof,
    )
    from ctypes.wintypes import BOOL, DWORD, HANDLE

    LOCK_SH = 0  # the default
    LOCK_NB = 0x1  # LOCKFILE_FAIL_IMMEDIATELY
    LOCK_EX = 0x2  # LOCKFILE_EXCLUSIVE_LOCK

    # --- Adapted from the pyserial project ---
    # detect size of ULONG_PTR
    if sizeof(c_ulong) != sizeof(c_void_p):
        ULONG_PTR = c_int64
    else:
        ULONG_PTR = c_ulong
    PVOID = c_void_p

    # --- Union inside Structure by stackoverflow:3480240 ---
    class _OFFSET(Structure):
        _fields_ = [("Offset", DWORD), ("OffsetHigh", DWORD)]

    class _OFFSET_UNION(Union):
        _anonymous_ = ["_offset"]
        _fields_ = [("_offset", _OFFSET), ("Pointer", PVOID)]

    class OVERLAPPED(Structure):
        _anonymous_ = ["_offset_union"]
        _fields_ = [
            ("Internal", ULONG_PTR),
            ("InternalHigh", ULONG_PTR),
            ("_offset_union", _OFFSET_UNION),
            ("hEvent", HANDLE),
        ]

    LPOVERLAPPED = POINTER(OVERLAPPED)

    # --- Define function prototypes for extra safety ---
    kernel32 = WinDLL("kernel32")
    LockFileEx = kernel32.LockFileEx
    LockFileEx.restype = BOOL
    LockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, DWORD, LPOVERLAPPED]
    UnlockFileEx = kernel32.UnlockFileEx
    UnlockFileEx.restype = BOOL
    UnlockFileEx.argtypes = [HANDLE, DWORD, DWORD, DWORD, LPOVERLAPPED]

    def lock(f, flags):
        hfile = msvcrt.get_osfhandle(_fd(f))
        overlapped = OVERLAPPED()
        ret = LockFileEx(hfile, flags, 0, 0, 0xFFFF0000, byref(overlapped))
        return bool(ret)

    def unlock(f):
        hfile = msvcrt.get_osfhandle(_fd(f))
        overlapped = OVERLAPPED()
        ret = UnlockFileEx(hfile, 0, 0, 0xFFFF0000, byref(overlapped))
        return bool(ret)

else:
    try:
        import fcntl

        LOCK_SH = fcntl.LOCK_SH  # shared lock
        LOCK_NB = fcntl.LOCK_NB  # non-blocking
        LOCK_EX = fcntl.LOCK_EX
    except (ImportError, AttributeError):
        # File locking is not supported.
        LOCK_EX = LOCK_SH = LOCK_NB = 0

        # Dummy functions that don't do anything.
        def lock(f, flags):
            # File is not locked
            return False

        def unlock(f):
            # File is unlocked
            return True

    else:

        def lock(f, flags):
            try:
                fcntl.flock(_fd(f), flags)
                return True
            except BlockingIOError:
                return False

        def unlock(f):
            fcntl.flock(_fd(f), fcntl.LOCK_UN)
            return True

总结

对于 web 服务端开发,文件操作是日常。但是文件的用途有很多,处置方式也很多。例如不同的文件类型放置在不同的存储后端,以及文件的访问控制、时效性也可以通过拓展存储后端来实现。

利用 django 这种分离文件操作和存储后端的框架,在开发中可以很好的解决大部分文件类需求。

相关推荐
陈随易3 分钟前
VSCode v1.102发布,AI体验大幅提升
前端·后端·程序员
小眼睛羊羊3 分钟前
pyinstaller打包paddleocr
python
java1234_小锋8 分钟前
基于Python的旅游推荐协同过滤算法系统(去哪儿网数据分析及可视化(Django+echarts))
python·数据分析·旅游
蓝婷儿9 分钟前
Python 机器学习核心入门与实战进阶 Day 4 - 支持向量机(SVM)原理与分类实战
python·机器学习·支持向量机
生无谓17 分钟前
什么是跨域,如何处理跨域
后端
Smilejudy18 分钟前
极具特色的位置运算
后端
码出极致19 分钟前
支付线上问题复盘的“5W”框架
后端
LuckyLay22 分钟前
1.1.1数据类型与变量——AI教你学Django
数据库·django·sqlite
ezl1fe27 分钟前
RAG 每日一技(三):不止文本,代码和Markdown如何优雅地分块?
后端
jack_yin28 分钟前
手把手教你玩转 telegram-deepseek-bot 的 Admin 管理后台!
后端