aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--account/extra.py38
-rw-r--r--account/models.py50
2 files changed, 87 insertions, 1 deletions
diff --git a/account/extra.py b/account/extra.py
index c247b8f..6ff19b2 100644
--- a/account/extra.py
+++ b/account/extra.py
@@ -6,9 +6,14 @@ Extra models for app account
from django.db import models
from django import forms
+from django.core.files.storage import FileSystemStorage
+from django.conf import settings
from django.template.defaultfilters import filesizeformat
from django.utils.translation import ugettext_lazy as _
+import os
+
+
class ContentTypeRestrictedFileField(models.FileField):
"""
Same as FileField, but you can specify:
@@ -48,3 +53,36 @@ class ContentTypeRestrictedFileField(models.FileField):
#
return data
+
+### OverwriteStorage ###
+class OverwriteStorage(FileSystemStorage):
+ """
+ overwrite original file before store the new one
+ """
+ def get_available_name(self, name):
+ """
+ Returns a filename that's free on the target storage system,
+ and available for new content to be written to.
+ Ref: http://djangosnippets.org/snippets/976/
+
+ This file storage solves overwrite on upload problem. Another
+ proposed solution was to override the save method on the model
+ like so (from https://code.djangoproject.com/ticket/11663):
+
+ def save(self, *args, **kwargs):
+ try:
+ this = MyModelName.objects.get(id=self.id)
+ if this.MyImageFieldName != self.MyImageFieldName:
+ this.MyImageFieldName.delete()
+ except: pass
+ super(MyModelName, self).save(*args, **kwargs)
+ """
+ # If the filename already exists,
+ # remove it as if it was a true file system
+ if self.exists(name):
+ filepath = os.path.join(settings.MEDIA_ROOT, name)
+ if os.path.isfile(filepath):
+ os.remove(filepath)
+ return name
+
+
diff --git a/account/models.py b/account/models.py
index 257477d..cb806da 100644
--- a/account/models.py
+++ b/account/models.py
@@ -6,12 +6,14 @@
from django.db import models
from django.contrib.auth.models import User
+from django.db.models.fields.files import FieldFile
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
+from django.db.models.signals import pre_delete
from registration.signals import user_registered
-from account.extra import ContentTypeRestrictedFileField
+from account.extra import ContentTypeRestrictedFileField, OverwriteStorage
###### account models ######
@@ -68,6 +70,7 @@ class UserProfile(models.Model):
# transcript: needed if undergraudate (junior and below)
transcript = ContentTypeRestrictedFileField(upload_to=lambda instance, filename: u'account/{0}/{1}'.format(instance.user.username, filename),
verbose_name=_("Transcript"), blank=True, null=True,
+ storage=OverwriteStorage(),
content_types=settings.ALLOWED_CONTENT_TYPES,
max_upload_size=settings.ALLOWED_MAX_UPLOAD_SIZE)
# supplement: record additional information
@@ -85,6 +88,18 @@ class UserProfile(models.Model):
def __unicode__(self):
return u'UserProfile for %s' % self.user.username
+ def save(self, *args, **kwargs):
+ """
+ overwrite the original save method to delete old file
+ """
+ old_obj = type(self).objects.get(pk=self.pk)
+ result = super(UserProfile, self).save(*args, **kwargs)
+ # if the path is the same, the file is overwritten already
+ if old_obj.transcript.path != self.transcript.path:
+ old_obj.transcript.delete(save=False)
+ #
+ return result
+
def is_transcript_required(self):
"""
if 'identify' is UG (undergraduate junior and below); then
@@ -152,6 +167,7 @@ class UserFile(models.Model):
description = models.TextField(_("Description"), blank=True)
file = ContentTypeRestrictedFileField(upload_to=lambda instance, filename: u'account/{0}/{1}'.format(instance.user.username, filename),
verbose_name=_("File"),
+ storage = OverwriteStorage(),
content_types=settings.ALLOWED_CONTENT_TYPES,
max_upload_size=settings.ALLOWED_MAX_UPLOAD_SIZE)
created_at = models.DateTimeField(_("Created time"),
@@ -166,6 +182,18 @@ class UserFile(models.Model):
def __unicode__(self):
return u'UserFile of %s: %s' % (self.user.username, self.title)
+ def save(self, *args, **kwargs):
+ """
+ overwrite the original save method to delete old file
+ """
+ old_obj = type(self).objects.get(pk=self.pk)
+ result = super(UserFile, self).save(*args, **kwargs)
+ # if the path is the same, the file is overwritten already
+ if old_obj.file.path != self.file.path:
+ old_obj.file.delete(save=False)
+ #
+ return result
+
###### signal callback ######
def user_registered_callback(sender, user, request, **kwargs):
@@ -185,3 +213,23 @@ def user_registered_callback(sender, user, request, **kwargs):
user_registered.connect(user_registered_callback)
+### delete files associated with model FileField
+# Pre-delete signal function for deleting files a model
+# https://djangosnippets.org/snippets/2820/
+def file_cleanup(sender, instance, *args, **kwargs):
+ """
+ Deletes the file(s) associated with a model instance. The model
+ is not saved after deletion of the file(s) since this is meant
+ to be used with the pre_delete signal.
+ """
+ for field_name, _ in instance.__dict__.iteritems():
+ field = getattr(instance, field_name)
+ if (issubclass(field.__class__, FieldFile) and field.name):
+ # pass False so FileField does not save the model
+ field.delete(save=False)
+
+### connect to signal and sender
+pre_delete.connect(file_cleanup, sender=UserProfile)
+pre_delete.connect(file_cleanup, sender=UserFile)
+
+