实现model中的文件上传FTP(二)

上一篇博客记录了如何将model中的图片存入FTP,通过一个第三方的storages简单的实现了,但是后续我发现如果想在浏览器通过url直接获取图片,就不太容易了(大神轻喷,小弟自学django和python,基础知识差),于是我从头开始学习,当浏览器输入一段URL的时候,django后台究竟做了什么

 

一.URL处理

django在处理我们自己设计的业务请求的时候都会通过urls.py这里面的url()方法处理

def url(regex, view, kwargs=None, name=None):
    if isinstance(view, (list, tuple)):
        # For include(...) processing.
        urlconf_module, app_name, namespace = view
        return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)
    elif callable(view):
        return RegexURLPattern(regex, view, kwargs, name)
    else:
        raise TypeError('view must be a callable or a list/tuple in the case of include().')

简单的使用过url()或者看url的源码都知道,这里的第一个参数是获取端口号后面的url字符,用来做正则匹配的,第二个参数是处理这个请求的view方法,由于我想请求的是一个图片,只是一个静态文件,所以我联想到django在处理静态文件的url的时候,应该也会有一个特殊的方法去处理,而且这个方法是依赖setting中的debug模式是否开启(这也就是为什么关了debug,部署到服务器上的时候,django自身是提供不了静态文件的访问,因为web服务器更适合做这些工作),但是在这里卡住了。。。不知道要怎么去找这个方法,查了好久资料也没有找到,后来我想起了django的media应该和静态文件是一样的

(r'^site_media/(?P<path>.*)$', 'django.views.static.serve',{'document_root': settings.STATIC_PATH}),

这个media是一般处理用户上传的文件之类的,于是我找到了django.views.static.serve方法

def serve(request, path, document_root=None, show_indexes=False):
    ......
    content_type, encoding = mimetypes.guess_type(fullpath)
    content_type = content_type or 'application/octet-stream'
    response = FileResponse(open(fullpath, 'rb'), content_type=content_type)
    response["Last-Modified"] = http_date(statobj.st_mtime)
    if stat.S_ISREG(statobj.st_mode):
        response["Content-Length"] = statobj.st_size
    if encoding:
        response["Content-Encoding"] = encoding
    return response

 

这个方法前面我省略了,大概就是判断一下URL指向的是否是一个文件,如果不是就返回报错了,真正处理的是这部分,它是返回了一个FileResponse的一个类型,看名字可以发现应该是直接返回一个文件,其实在这里我踩了好多坑,一直不知道如何给浏览器直接返回一个文件,甚至都已经把二进制文件获取到了,但是直接返回给浏览器就是乱码。。。。,不知道是不是根本原因,前端知识有限,这个FileResponse会附带一个content_type,这是一个http返回的header,将类型指定为图片,就可以展示出来了,至于这个类型,看源码也可以看到,前面用了一个mimetypes.guess_type()的方法,我大致了解了一下,这个方法只需要传URL给它就可以了,它会根据这个 URL的后缀判断,不会真的去把这个文件拿到再判断,所以不用担心它会再一次去ftp里取文件。此外,还有一些其他的header也可以设置,但是这里只用到type应该就可以了,其他的header看自己的需求

参考到这里,我们可以知道,大致思路就是自己需要重写一个url里media的view方法,用这个方法取到图片,然后返回给前端就可以了

一.get_from_ftp

这里我重写一个get_from_ftp方法来实现,其实这里我走了许多弯路。。。不知道要怎么通过storage获取到文件,而且也不知道对应的参数是什么,我这里查阅了大量的资料,然后一路碰壁,各种看源码,各种猜测,打断点。。。中间的经历过于痛苦,就不细说了(主要原因还是自己没有经验,这次也算学习到了思路),主要就是看其他地方是如何使用storage的,然后我使用的是第三方重写的ftpstorage,和其他的storage一样,是通过open方法来获取文件,参数就是路径+文件名,其实这里可以直接用media的url传过来的参数  '^media/(?P<path>.*)$'  

url.py

url(r'^media/(?P<path>.*)$', get_from_ftp),

get_from_ftp

def get_from_ftp(request,path):
    storage=FTPStorage()
    file=storage.open(path)
    content_type, encoding=mimetypes.guess_type(path)
    return FileResponse(file, content_type=content_type)

 

其实很简单的一个逻辑,只要知道storage如何使用,很轻松就可以完成这一过程,主要还是要养成好的思考习惯,多看源码,多看文档

 

posted on 2018-04-13 14:24  小小白鸽  阅读(612)  评论(0编辑  收藏  举报