[PATCH] FileField with custom upload_to

62 views
Skip to first unread message

Jay Parlar

unread,
May 24, 2006, 10:26:17 AM5/24/06
to django...@googlegroups.com
Is this patch useful/correct enough to warrant submitting a ticket?


Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py (revision 2970)
+++ django/db/models/fields/__init__.py (working copy)
@@ -568,7 +568,13 @@
setattr(cls, 'get_%s_filename' % self.name,
curry(cls._get_FIELD_filename, field=self))
setattr(cls, 'get_%s_url' % self.name,
curry(cls._get_FIELD_url, field=self))
setattr(cls, 'get_%s_size' % self.name,
curry(cls._get_FIELD_size, field=self))
- setattr(cls, 'save_%s_file' % self.name, lambda instance,
filename, raw_contents: instance._save_FIELD_file(self, filename,
raw_contents))
+
+ def save_func(instance, filename, raw_contents, upload_to=""):
+ if upload_to:
+ self.upload_to = upload_to
+ instance._save_FIELD_file(self, filename, raw_contents)
+ setattr(cls, 'save_%s_file' % self.name, save_func)
+
dispatcher.connect(self.delete_file,
signal=signals.post_delete, sender=cls)

def delete_file(self, instance):


Essentially, I wanted a way to define the upload_to when I do the
save, not in the model. This way I can have files from the same model
easily go to different directories.


Jay P.

Ivan Sagalaev

unread,
May 24, 2006, 11:18:58 AM5/24/06
to django...@googlegroups.com
Jay Parlar wrote:

>+ def save_func(instance, filename, raw_contents, upload_to=""):
>+ if upload_to:
>+ self.upload_to = upload_to
>+ instance._save_FIELD_file(self, filename, raw_contents)
>+ setattr(cls, 'save_%s_file' % self.name, save_func)
>
>

I would prefer self.upload_to to be restored to its original value after
call. Otherwise a call to save_*_file with a custom parameter would
change object's "global" behavior which is very counter-intuitive. In
fact I think custom upload_to should be passed further down to
_save_FIELD_file and replaced there locally.

Jay Parlar

unread,
May 24, 2006, 11:39:00 AM5/24/06
to django...@googlegroups.com
On 5/24/06, Ivan Sagalaev <Man...@softwaremaniacs.org> wrote:

> I would prefer self.upload_to to be restored to its original value after
> call. Otherwise a call to save_*_file with a custom parameter would
> change object's "global" behavior which is very counter-intuitive. In
> fact I think custom upload_to should be passed further down to
> _save_FIELD_file and replaced there locally.


Ok, that makes a lot of sense, especiallt the part about not changing
the global behaviour.

Try #2:


Index: django/db/models/base.py
===================================================================
--- django/db/models/base.py (revision 2970)
+++ django/db/models/base.py (working copy)
@@ -300,13 +300,14 @@
def _get_FIELD_size(self, field):
return os.path.getsize(self._get_FIELD_filename(field))

- def _save_FIELD_file(self, field, filename, raw_contents):
- directory = field.get_directory_name()
+ def _save_FIELD_file(self, field, filename, raw_contents, custom_upload_to=
""):
+
+ directory = field.get_directory_name(custom_upload_to)
try: # Create the date-based directory if it doesn't exist.
os.makedirs(os.path.join(settings.MEDIA_ROOT, directory))
except OSError: # Directory probably already exists.
pass
- filename = field.get_filename(filename)
+ filename = field.get_filename(filename, custom_upload_to)

# If the filename already exists, keep adding an underscore to the name
of
# the file until the filename doesn't exist.
Index: django/db/models/fields/__init__.py
===================================================================
--- django/db/models/fields/__init__.py (revision 2977)
+++ django/db/models/fields/__init__.py (working copy)
@@ -568,7 +568,9 @@


setattr(cls, 'get_%s_filename' % self.name, curry(cls._get_FIELD_filena
me, field=self))
setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=
self))
setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, fiel
d=self))
- setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw
_contents: instance._save_FIELD_file(self, filename, raw_contents))

+ def save_func(instance, filename, raw_contents, upload_to=""):

+ instance._save_FIELD_file(self, filename, raw_contents, upload_to)


+ setattr(cls, 'save_%s_file' % self.name, save_func)

dispatcher.connect(self.delete_file, signal=signals.post_delete, sender
=cls)

def delete_file(self, instance):
@@ -595,14 +597,19 @@
else:
func(new_data[upload_field_name]["filename"], new_data[upload_f
ield_name]["content"])

- def get_directory_name(self):
- return os.path.normpath(datetime.datetime.now().strftime(self.upload_to
))
+ def get_directory_name(self, custom_upload_to=""):
+ upload_to = self.upload_to
+ if custom_upload_to:
+ upload_to = custom_upload_to
+ return os.path.normpath(datetime.datetime.now().strftime(upload_to))

- def get_filename(self, filename):
+ def get_filename(self, filename, custom_upload_to):
from django.utils.text import get_valid_filename
- f = os.path.join(self.get_directory_name(), get_valid_filename(os.path.
basename(filename)))
+ f = os.path.join(self.get_directory_name(custom_upload_to), get_valid_f
ilename(os.path.basename(filename)))
return os.path.normpath(f)

+
+
class FilePathField(Field):
def __init__(self, verbose_name=None, name=None, path='', match=None, recur
sive=False, **kwargs):
self.path, self.match, self.recursive = path, match, recursive


Jay P.

Jay Parlar

unread,
May 24, 2006, 8:31:26 PM5/24/06
to django...@googlegroups.com
I went ahead and filed a patch with Trac,
http://code.djangoproject.com/ticket/1994

Jay P.

medhat

unread,
Jun 2, 2006, 6:12:23 PM6/2/06
to Django users

I like this solution... actually, I was trying to achieve something
similar and came up with an almost identical solution. So, I am +1 for
this patch.

--
Thanks,
Medhat

Reply all
Reply to author
Forward
0 new messages