直接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
"""