Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Websites UFRPE
Django Private Storage
Commits
c7abf477
Commit
c7abf477
authored
Feb 07, 2017
by
Diederik van der Boor
Browse files
Support streaming responses from the storage class
This is needed to fetch content from S3 without needing a full_path
parent
eecfc006
Changes
4
Show whitespace changes
Inline
Side-by-side
private_storage/models.py
View file @
c7abf477
import
mimetypes
import
mimetypes
import
os
from
django.core.files.storage
import
Storage
,
File
from
django.utils.functional
import
cached_property
from
django.utils.functional
import
cached_property
...
@@ -11,7 +11,7 @@ class PrivateFile(object):
...
@@ -11,7 +11,7 @@ class PrivateFile(object):
def
__init__
(
self
,
request
,
storage
,
relative_name
):
def
__init__
(
self
,
request
,
storage
,
relative_name
):
self
.
request
=
request
self
.
request
=
request
self
.
storage
=
storage
self
.
storage
=
storage
# type: Storage
self
.
relative_name
=
relative_name
self
.
relative_name
=
relative_name
@
cached_property
@
cached_property
...
@@ -19,13 +19,38 @@ class PrivateFile(object):
...
@@ -19,13 +19,38 @@ class PrivateFile(object):
# Not using self.storage.open() as the X-Sendfile needs a normal path.
# Not using self.storage.open() as the X-Sendfile needs a normal path.
return
self
.
storage
.
path
(
self
.
relative_name
)
return
self
.
storage
.
path
(
self
.
relative_name
)
def
open
(
self
,
mode
=
'rb'
):
"""
Open the file for reading.
:rtype: django.core.files.storage.File
"""
file
=
self
.
storage
.
open
(
self
.
relative_name
,
mode
=
mode
)
# type: File
return
file
def
exists
(
self
):
def
exists
(
self
):
return
os
.
path
.
exists
(
self
.
full_path
)
"""
Check whether the file exists.
"""
return
self
.
storage
.
exists
(
self
.
relative_name
)
@
cached_property
@
cached_property
def
content_type
(
self
):
def
content_type
(
self
):
"""
"""
Return the HTTP ``Content-Type`` header value for a filename.
Return the HTTP ``Content-Type`` header value for a filename.
"""
"""
mimetype
,
encoding
=
mimetypes
.
guess_type
(
self
.
full_path
)
mimetype
,
encoding
=
mimetypes
.
guess_type
(
self
.
relative_name
)
return
mimetype
or
'application/octet-stream'
return
mimetype
or
'application/octet-stream'
@
cached_property
def
size
(
self
):
"""
Return the size of the file in bytes.
"""
return
self
.
storage
.
size
(
self
.
relative_name
)
@
cached_property
def
modified_time
(
self
):
"""
Return the last-modified time
"""
return
self
.
storage
.
get_modified_time
(
self
.
relative_name
)
private_storage/servers.py
View file @
c7abf477
...
@@ -5,7 +5,8 @@ import os
...
@@ -5,7 +5,8 @@ import os
from
django.conf
import
settings
from
django.conf
import
settings
from
django.core.exceptions
import
ImproperlyConfigured
from
django.core.exceptions
import
ImproperlyConfigured
from
django.http
import
HttpResponse
from
django.http
import
FileResponse
,
HttpResponse
from
django.utils.http
import
http_date
from
django.utils.lru_cache
import
lru_cache
from
django.utils.lru_cache
import
lru_cache
from
django.utils.module_loading
import
import_string
from
django.utils.module_loading
import
import_string
from
django.views.static
import
serve
from
django.views.static
import
serve
...
@@ -15,6 +16,8 @@ from django.views.static import serve
...
@@ -15,6 +16,8 @@ from django.views.static import serve
def
get_server_class
(
path
):
def
get_server_class
(
path
):
if
'.'
in
path
:
if
'.'
in
path
:
return
import_string
(
path
)
return
import_string
(
path
)
elif
path
==
'streaming'
:
return
DjangoStreamingServer
elif
path
==
'django'
:
elif
path
==
'django'
:
return
DjangoServer
return
DjangoServer
elif
path
==
'apache'
:
elif
path
==
'apache'
:
...
@@ -27,7 +30,22 @@ def get_server_class(path):
...
@@ -27,7 +30,22 @@ def get_server_class(path):
)
)
class
DjangoServer
(
object
):
class
DjangoStreamingServer
(
object
):
"""
Serve static files as streaming chunks in Django.
"""
@
staticmethod
def
serve
(
private_file
):
# FileResponse will submit the file in 8KB chunks
response
=
FileResponse
(
private_file
.
open
())
response
[
'Content-Type'
]
=
private_file
.
content_type
response
[
'Content-Length'
]
=
private_file
.
size
response
[
"Last-Modified"
]
=
http_date
(
private_file
.
modified_time
.
timestamp
())
return
response
class
DjangoServer
(
DjangoStreamingServer
):
"""
"""
Serve static files from the local filesystem through Django.
Serve static files from the local filesystem through Django.
This is a bad idea for most situations other than testing.
This is a bad idea for most situations other than testing.
...
@@ -38,7 +56,14 @@ class DjangoServer(object):
...
@@ -38,7 +56,14 @@ class DjangoServer(object):
@
staticmethod
@
staticmethod
def
serve
(
private_file
):
def
serve
(
private_file
):
# This supports If-Modified-Since and sends the file in 8KB chunks
# This supports If-Modified-Since and sends the file in 8KB chunks
return
serve
(
private_file
.
request
,
private_file
.
full_path
,
document_root
=
'/'
,
show_indexes
=
False
)
try
:
full_path
=
private_file
.
full_path
except
NotImplementedError
:
# S3 files, fall back to streaming server
return
DjangoStreamingServer
.
serve
(
private_file
)
else
:
# Using Django's serve gives If-Modified-Since support out of the box.
return
serve
(
private_file
.
request
,
full_path
,
document_root
=
'/'
,
show_indexes
=
False
)
class
ApacheXSendfileServer
(
object
):
class
ApacheXSendfileServer
(
object
):
...
...
private_storage/views.py
View file @
c7abf477
...
@@ -85,7 +85,7 @@ class PrivateStorageDetailView(SingleObjectMixin, PrivateStorageView):
...
@@ -85,7 +85,7 @@ class PrivateStorageDetailView(SingleObjectMixin, PrivateStorageView):
def
get_path
(
self
):
def
get_path
(
self
):
file
=
getattr
(
self
.
object
,
'file'
)
file
=
getattr
(
self
.
object
,
'file'
)
return
file
.
path
return
file
.
name
def
can_access_file
(
self
,
private_file
):
def
can_access_file
(
self
,
private_file
):
"""
"""
...
...
setup.py
View file @
c7abf477
...
@@ -40,7 +40,7 @@ setup(
...
@@ -40,7 +40,7 @@ setup(
install_requires
=
[],
install_requires
=
[],
requires
=
[
requires
=
[
'Django (>=1.7)'
,
'Django (>=1.7
.4
)'
,
],
],
description
=
'Private media file storage for Django projects'
,
description
=
'Private media file storage for Django projects'
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment