For the projects I'm working on, we have a reusable "image file" model which stores information about an image (such as height, width, hash, image type, etc) and automatically stashes it to Amazon S3.
Any time you want to use an image in another model, you can just refer to it through a foreign key.
1.
class
BasicImage(models.Model):
2.
caption
=
models.CharField(max_length
=
300
, blank
=
True
)
3.
# ...
4.
image
=
models.ImageField(storage
=
s3_storage, upload_to
=
"images"
, max_length
=
500
)
5.
6.
def
__unicode__(
self
):
7.
return
"%s - %s"
%
(
self
.caption,
self
.image)
And an example of a model which uses BasicImage.
1.
class
UserProfile(models.Model):
2.
# ...
3.
profile_picture
=
models.ForeignKey(BasicImage)
Whenever a user uploads a profile picture, it'll be uploaded to a folder called "images", along with every other image file. That's fine and dandy if you're ok with mixing user profile pictures with other images (such as company logos or user photos).
However, most people would like to separate things out a bit. Here's a relatively clean way of preventing a huge binary mess. (Key points are listed below)
01.
def
_image_upload_path(instance, filename):
02.
# To customise the path which the image saves to.
03.
return
instance.get_upload_path(filename)
04.
05.
06.
class
BasicImage(models.Model):
07.
caption
=
models.CharField(max_length
=
300
, blank
=
True
)
08.
# ...
09.
image
=
models.ImageField(storage
=
s3_storage, upload_to
=
_image_upload_path, max_length
=
500
)
10.
11.
def
__unicode__(
self
):
12.
return
"%s - %s"
%
(
self
.caption,
self
.image)
13.
14.
def
get_upload_path(
self
, filename):
15.
return
"dimg/%s"
%
filename
16.
17.
18.
# Required to add new files to a different path
19.
class
UserProfileImage(BasicImage):
20.
class
Meta:
21.
proxy
=
True
# So this model doesn't actually need a new table
22.
23.
def
get_upload_path(
self
, filename):
24.
return
"avatars/%s"
%
filename
25.
26.
27.
# Updated user model so any pictures will be uploaded to /avatars folder
28.
class
UserProfile(models.Model):
29.
user
=
models.OneToOneField(User, primary_key
=
True
)
30.
# ...
31.
profile_picture
=
models.ForeignKey(UserProfileImage)
Take note of the differences:
- Create a helper function called _image_upload_path()
- Add BasicImage.get_upload_path(self, filename)
- You'll need to use BasicImage as a base class for any other image models
- Other image models should be a proxy class unless they contain additional information
- Override get_upload_path() in your subclasses if you wish to customise the upload folder
Now you can upload random pictures like this into a separate folder