django改文件存儲爲fastdfs

直接pip install py3fdfs安裝,安裝完以後使用:

from fdfs_client.client import *
client = Fdfs_client('/etc/fdfs/client.conf')

然後給你來個異常,TypeError: type object argument after ** must be a mapping, not str,這一看就是傳入參數不對,要傳一個字典吧估計,Fdfs_client裏的構造函數是這樣的

def __init__(self, trackers, poolclass=ConnectionPool):
    self.trackers = trackers
    self.tracker_pool = poolclass(**self.trackers)
    self.timeout = self.trackers['timeout']
    return None


trackers裏發現一個[‘timeout’],看來是要傳入這麼個key,繼續找ConnectionPool

def __init__(self, **conn_kwargs):
    self.pid = os.getpid()
    self.host_tuple = conn_kwargs['host_tuple']
    self.remote_port = conn_kwargs['port']
    self.remote_addr = None
   self.timeout = conn_kwargs['timeout']
    self._sock = None

還有host和端口,看來這是要把client.conf那些配置項都傳進去,那隻能先傳着嘍,

client = Fdfs_client({'host_tuple': '64.19.202.73', 'port': 22122, 'timeout': 30})
 

client.upload_by_filename('test')
[-] Error: 11001 connect to 0:22122. getaddrinfo failed.
[-] Error: 11001 connect to 7:22122. getaddrinfo failed.
[-] Error: 11001 connect to 0:22122. getaddrinfo failed.
[-] Error: 11001 connect to 2:22122. getaddrinfo failed.
[-] Error: 11001 connect to 4:22122. getaddrinfo failed.
Traceback (most recent call last):
  File "C:\Users\JanmChen\AppData\Local\Programs\Python\Python37-32\lib\site-packages\fdfs_client\connection.py", line 129, in get_connection
    conn = self._conns_available.pop()
IndexError: pop from empty list
bla bla...

顯示失敗,那就應該是host_tuple的問題了,估計可以傳多個,那就傳列表吧,

client = Fdfs_client({'host_tuple': ['64.19.202.73'], 'port': 22122, 'timeout': 30, 'name': 'Tracker Pool'})
client.upload_by_filename(r'D:\文檔\python\web\mysite\static\favicon.ico')
{'Group name': b'group1', 'Remote file_id': b'group1/M00/00/00/rBE_J1yjbWKAVExPAAAQvv-sBWc759.ico', 'Status': 'Upload successed.', 'Local file name': 'D:\\文檔\\python\\web\\mysite\\static\\favicon.ico', 'Uploaded size': '4.19KB', 'Storage IP': b'139.24.13.15'}

很好,這一步就完成了,其實就在Fdfs_client類的上邊就有一個get_tracker_conf函數,裏邊就定義好了從配置文件取出各項返回一個tracker字典

def get_tracker_conf(conf_path='client.conf'):
    cf = Fdfs_ConfigParser()
    tracker = {}
    try:
        cf.read(conf_path)
        timeout = cf.getint('__config__', 'connect_timeout')
        tracker_list = cf.get('__config__', 'tracker_server')
        if isinstance(tracker_list, str):
            tracker_list = [tracker_list]
        tracker_ip_list = []
        for tr in tracker_list:
            tracker_ip, tracker_port = tr.split(':')
            tracker_ip_list.append(tracker_ip)
        tracker['host_tuple'] = tuple(tracker_ip_list)
        tracker['port'] = int(tracker_port)
        tracker['timeout'] = timeout
        tracker['name'] = 'Tracker Pool'
    except:
        raise
    return tracker

這下就明朗了,再看一下這個函數到底給你返回啥東西

get_tracker_conf('D://文檔/python/web/mysite/utils/fdfs_client.conf')
{'host_tuple': ('64.190.202.73',), 'port': 22122, 'timeout': 30, 'name': 'Tracker Pool'}

不錯,跟我猜測的差不多,它用的是元組,這個坑填完了,接下來繼續

在setting.py增加以下內容

# 配置django文件存儲爲fdfs
DEFAULT_FILE_STORAGE = 'utils.fdfs_storage.FdfsStorage
# Fdfs存儲參數 客戶端配置文件同服務器端,服務器地址
SERVER_IP = 'http://139.224.13.1'
CUSTOM_STORAGE_OPTIONS = {
    'CLIENT_CONF': './utils/fdfs_client.conf',
    'BASE_URL': SERVER_IP + ':8888/',
}
然後可以定義自己的storage類了,這裏注意以下_save的返回值就行,跟之前的又不一樣了,但報錯消息一目瞭然

from django.core.files.storage import Storage
from django.conf import settings
from fdfs_client.client import Fdfs_client, get_tracker_conf
from django.utils.deconstruct import deconstructible


# 存儲類必須是:ref:deconstructible,以便在遷移中的字段上使用它時可以序列化。 只要你的字段有自己的參數:ref:serializable,
# 你可以使用django.utils.deconstruct.deconstructible類裝飾器(這是Django在FileSystemStorage上使用的)
@deconstructible
class FdfsStorage(Storage):
    def __init__(self, option=None):
        if not option:
            self.option = settings.CUSTOM_STORAGE_OPTIONS
        else:
            self.option = option

    def _open(self, name, mode='rb'):
        """
        用不到打開文件,所以省略
        """
        pass

    def _save(self, name, content):
        """
        在FastDFS中保存文件
        :param name: 傳入的文件名
        :param content: 文件內容
        :return: 保存到數據庫中的FastDFS的文件名
        """
        client_conf_obj = get_tracker_conf(self.option.get('CLIENT_CONF'))
        client = Fdfs_client(client_conf_obj)
        ret = client.upload_by_buffer(content.read())
        if ret.get("Status") != "Upload successed.":
            raise Exception("upload file failed")
        file_name = ret.get("Remote file_id")

        # file_name爲bytes類型,只能返回str類型,不然會報錯
        return file_name.decode()

    def url(self, name):
        """
        返回文件的完整URL路徑
        :param name: 數據庫中保存的文件名
        :return: 完整的URL
        """
        return self.option.get('BASE_URL') + name

    def exists(self, name):
        """
        判斷文件是否存在,FastDFS可以自行解決文件的重名問題
        所以此處返回False,告訴Django上傳的都是新文件
        :param name:  文件名
        :return: False
        """

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章