Last active
March 27, 2019 15:17
-
-
Save JordanReiter/29619a19c1075c91f82ed16927ab7985 to your computer and use it in GitHub Desktop.
File field for files stored in S3 that provides easy access to previous versions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Adds access to previous versions to a model's file field. | |
Requires django-storages, and you must either be using S3Boto3Storage | |
by default, or you must specify it as the storage class in the field | |
definition. | |
class SampleModel(models.Model): | |
file = S3FileField(upload_to='path/to/dir') | |
>> record = SampleModel.objects.all()[0] | |
>> record.file | |
<S3FieldFile: path/to/dir/filename.docx> | |
>> record.file.versions | |
<S3FileVersions: {1: <Key: bucket_name,path/to/dir/filename.docx>, 2: <Key: bucket_name,path/to/dir/filename.docx>, | |
3: <Key: bucket_name,path/to/dir/filename.docx>}> | |
>> record.file.versions.first | |
<Key: bucket_name,path/to/dir/filename.docx> | |
>> record.file.versions.first.version | |
1 | |
>> record.file.versions.first.date | |
datetime.datetime(2019, 1, 1, 8, 25, 45) | |
>> record.file.versions.first.url | |
https://s3.amazonaws.com:443/bucket_name/path/to/dir/filename.docx?Signature=...&Expires=...&AWSAccessKeyId=...&versionId=... | |
>> record.file.versions[2].date | |
datetime.datetime(2019, 1, 3, 11, 8, 11) | |
>> record.file.versions[2].version | |
2 | |
>> record.file.versions.previous.version | |
2 | |
>> record.file.versions.current.version | |
3 | |
''' | |
class S3FileVersions: | |
def __init__(self, current, versions, expires_in=None): | |
expires_in = expires_in or 100 | |
self.versions = {} | |
for vv_idx, vv in enumerate(sorted(versions, key=lambda x: x.last_modified)): | |
setattr(vv, 'date', datetime.datetime.strptime(vv.last_modified, '%Y-%m-%dT%H:%M:%S.%fZ')) | |
setattr(vv, 'version', vv_idx + 1) | |
setattr(vv, 'url', vv.generate_url(expires_in)) | |
self.versions[vv_idx + 1] = vv | |
if vv.version_id == current.version_id: | |
current = vv | |
self.current = current | |
def __iter__(self): | |
return iter(self.versions.values()) | |
@property | |
def previous(self): | |
return self.versions[max( | |
kk for kk, vv in | |
self.versions.items() | |
if vv.version_id != self.current.version_id | |
)] | |
@property | |
def first(self): | |
return self.versions[min(self.versions.keys())] | |
def __getitem__(self, version): | |
return self.versions[version] | |
def __repr__(self): | |
return '<S3FileVersions: {}>'.format(repr(self.versions)) | |
class S3FieldFile(FieldFile): | |
@property | |
def versions(self): | |
current = self.storage.bucket.get_key(self.name) | |
return S3FileVersions(current, self.storage.bucket.list_versions(self.name)) | |
class S3FileField(models.FileField): | |
attr_class = S3FieldFile |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment