mirror of
https://github.com/django/django.git
synced 2025-10-25 22:56:12 +00:00
Fixed #23832 -- Added timezone aware Storage API.
New Storage.get_{accessed,created,modified}_time() methods convert the
naive time from now-deprecated {accessed,created_modified}_time()
methods into aware objects in UTC if USE_TZ=True.
This commit is contained in:
@@ -237,15 +237,14 @@ class Command(BaseCommand):
|
||||
if self.storage.exists(prefixed_path):
|
||||
try:
|
||||
# When was the target file modified last time?
|
||||
target_last_modified = \
|
||||
self.storage.modified_time(prefixed_path)
|
||||
target_last_modified = self.storage.get_modified_time(prefixed_path)
|
||||
except (OSError, NotImplementedError, AttributeError):
|
||||
# The storage doesn't support ``modified_time`` or failed
|
||||
# The storage doesn't support get_modified_time() or failed
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
# When was the source file modified last time?
|
||||
source_last_modified = source_storage.modified_time(path)
|
||||
source_last_modified = source_storage.get_modified_time(path)
|
||||
except (OSError, NotImplementedError, AttributeError):
|
||||
pass
|
||||
else:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import errno
|
||||
import os
|
||||
import warnings
|
||||
from datetime import datetime
|
||||
|
||||
from django.conf import settings
|
||||
@@ -7,9 +8,11 @@ from django.core.exceptions import SuspiciousFileOperation
|
||||
from django.core.files import File, locks
|
||||
from django.core.files.move import file_move_safe
|
||||
from django.core.signals import setting_changed
|
||||
from django.utils import timezone
|
||||
from django.utils._os import abspathu, safe_join
|
||||
from django.utils.crypto import get_random_string
|
||||
from django.utils.deconstruct import deconstructible
|
||||
from django.utils.deprecation import RemovedInDjango20Warning
|
||||
from django.utils.encoding import filepath_to_uri, force_text
|
||||
from django.utils.functional import LazyObject, cached_property
|
||||
from django.utils.module_loading import import_string
|
||||
@@ -140,24 +143,101 @@ class Storage(object):
|
||||
def accessed_time(self, name):
|
||||
"""
|
||||
Returns the last accessed time (as datetime object) of the file
|
||||
specified by name.
|
||||
specified by name. Deprecated: use get_accessed_time() instead.
|
||||
"""
|
||||
warnings.warn(
|
||||
'Storage.accessed_time() is deprecated in favor of get_accessed_time().',
|
||||
RemovedInDjango20Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
raise NotImplementedError('subclasses of Storage must provide an accessed_time() method')
|
||||
|
||||
def created_time(self, name):
|
||||
"""
|
||||
Returns the creation time (as datetime object) of the file
|
||||
specified by name.
|
||||
specified by name. Deprecated: use get_created_time() instead.
|
||||
"""
|
||||
warnings.warn(
|
||||
'Storage.created_time() is deprecated in favor of get_created_time().',
|
||||
RemovedInDjango20Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
raise NotImplementedError('subclasses of Storage must provide a created_time() method')
|
||||
|
||||
def modified_time(self, name):
|
||||
"""
|
||||
Returns the last modified time (as datetime object) of the file
|
||||
specified by name.
|
||||
specified by name. Deprecated: use get_modified_time() instead.
|
||||
"""
|
||||
warnings.warn(
|
||||
'Storage.modified_time() is deprecated in favor of get_modified_time().',
|
||||
RemovedInDjango20Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
raise NotImplementedError('subclasses of Storage must provide a modified_time() 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.
|
||||
"""
|
||||
# At the end of the deprecation:
|
||||
# raise NotImplementedError('subclasses of Storage must provide a get_accessed_time() method')
|
||||
warnings.warn(
|
||||
'Storage.accessed_time() is deprecated. '
|
||||
'Storage backends should implement get_accessed_time().',
|
||||
RemovedInDjango20Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
dt = self.accessed_time(name)
|
||||
return _possibly_make_aware(dt)
|
||||
|
||||
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.
|
||||
"""
|
||||
# At the end of the deprecation:
|
||||
# raise NotImplementedError('subclasses of Storage must provide a get_created_time() method')
|
||||
warnings.warn(
|
||||
'Storage.created_time() is deprecated. '
|
||||
'Storage backends should implement get_created_time().',
|
||||
RemovedInDjango20Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
dt = self.created_time(name)
|
||||
return _possibly_make_aware(dt)
|
||||
|
||||
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.
|
||||
"""
|
||||
# At the end of the deprecation:
|
||||
# raise NotImplementedError('subclasses of Storage must provide a get_modified_time() method')
|
||||
warnings.warn(
|
||||
'Storage.modified_time() is deprecated. '
|
||||
'Storage backends should implement get_modified_time().',
|
||||
RemovedInDjango20Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
dt = self.modified_time(name)
|
||||
return _possibly_make_aware(dt)
|
||||
|
||||
|
||||
def _possibly_make_aware(dt):
|
||||
"""
|
||||
Convert a datetime object in the local timezone to aware
|
||||
in UTC, if USE_TZ is True.
|
||||
"""
|
||||
# This function is only needed to help with the deprecations above and can
|
||||
# be removed in Django 2.0, RemovedInDjango20Warning.
|
||||
if settings.USE_TZ:
|
||||
tz = timezone.get_default_timezone()
|
||||
return timezone.make_aware(dt, tz).astimezone(timezone.utc)
|
||||
else:
|
||||
return dt
|
||||
|
||||
|
||||
@deconstructible
|
||||
class FileSystemStorage(Storage):
|
||||
@@ -328,14 +408,52 @@ class FileSystemStorage(Storage):
|
||||
return urljoin(self.base_url, filepath_to_uri(name))
|
||||
|
||||
def accessed_time(self, name):
|
||||
warnings.warn(
|
||||
'FileSystemStorage.accessed_time() is deprecated in favor of '
|
||||
'get_accessed_time().',
|
||||
RemovedInDjango20Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return datetime.fromtimestamp(os.path.getatime(self.path(name)))
|
||||
|
||||
def created_time(self, name):
|
||||
warnings.warn(
|
||||
'FileSystemStorage.created_time() is deprecated in favor of '
|
||||
'get_created_time().',
|
||||
RemovedInDjango20Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return datetime.fromtimestamp(os.path.getctime(self.path(name)))
|
||||
|
||||
def modified_time(self, name):
|
||||
warnings.warn(
|
||||
'FileSystemStorage.modified_time() is deprecated in favor of '
|
||||
'get_modified_time().',
|
||||
RemovedInDjango20Warning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return datetime.fromtimestamp(os.path.getmtime(self.path(name)))
|
||||
|
||||
def _datetime_from_timestamp(self, ts):
|
||||
"""
|
||||
If timezone support is enabled, make an aware datetime object in UTC;
|
||||
otherwise make a naive one in the local timezone.
|
||||
"""
|
||||
if settings.USE_TZ:
|
||||
# Safe to use .replace() because UTC doesn't have DST
|
||||
return datetime.utcfromtimestamp(ts).replace(tzinfo=timezone.utc)
|
||||
else:
|
||||
return datetime.fromtimestamp(ts)
|
||||
|
||||
def get_accessed_time(self, name):
|
||||
return self._datetime_from_timestamp(os.path.getatime(self.path(name)))
|
||||
|
||||
def get_created_time(self, name):
|
||||
return self._datetime_from_timestamp(os.path.getctime(self.path(name)))
|
||||
|
||||
def get_modified_time(self, name):
|
||||
return self._datetime_from_timestamp(os.path.getmtime(self.path(name)))
|
||||
|
||||
|
||||
def get_storage_class(import_path=None):
|
||||
return import_string(import_path or settings.DEFAULT_FILE_STORAGE)
|
||||
|
||||
Reference in New Issue
Block a user