My solution is to override the model save method and check if the model is being created for the first time and also check if the postImage image field is empty. If so populate the postImage field with contents of a Radom image. Django will handle the rest
If we use the path of the Radom image directly in our model we will end up like serving some of the post model files from the media folder and some other from the static directory which is not recommended. Instead, we feed the image file content to the postImage field and Django will save the image to media folder and thus we can serve all our model images from media folder itself. Wola
Code
The following code is tested in Python 3.6
Please add the code to your models.py
from pathlib import Path
from random import randint
import time
from django.core.files import File
from django.db import models
allowed_image_extensions = ['.jpg', '.png', '.jpeg']
def get_file_extension(file_path):
return Path(file_path).suffix
def get_files_in_directory(directory, absolute_path=False):
from os import listdir
from os.path import isfile
only_files = [f for f in listdir(directory) if isfile("{}/{}".format(directory, f))]
if not absolute_path:
return only_files
else:
return ["{}/{}".format(directory, file_) for file_ in only_files]
def get_random_image_from_directory(directory_path, image_extension=None):
files_in_directory_path = get_files_in_directory(directory_path, absolute_path=True)
if image_extension:
allowed_file_types = [image_extension]
else:
allowed_file_types = allowed_image_extensions
# filter out files of type other than required file types
filtered_files_list = [_file for _file in files_in_directory_path if
get_file_extension(_file).lower() in allowed_file_types]
random_index = randint(0, len(filtered_files_list) - 1)
random_file_path = filtered_files_list[random_index]
random_file_content = File(open(random_file_path, 'rb'))
return random_file_content
def get_post_image_path(instance, filename):
path_first_component = 'posts'
ext = get_file_extension(filename)
current_time_stamp = int(time.time())
file_name = '{}/posts_{}_{}{}'.format(path_first_component, instance.id, current_time_stamp, ext)
full_path = path_first_component + file_name
return full_path
class Post(models.Model):
heading = models.CharField(max_length=150)
author = models.ForeignKey(User)
postBody = models.TextField()
postDate = models.DateTimeField('posting date')
postImage = models.ImageField(blank=True, null=True, upload_to=get_post_image_path)
# override model save method
def save(self, *args, **kwargs):
# check model is new and postImage is empty
if self.pk is None and not self.postImage:
random_image = get_random_image_from_directory(settings.STATIC_ROOT)
self.postImage = random_image
random_image.close()
super(Post, self).save(*args, **kwargs)
Also no need to set ‘/media’ in upload_to path. Django will read media path from settings variable
The best practice is to move those set of default images out of static directory to another folder probably another folder with name resources or any another meaningful name since the static directory contents will change frequently as the project grows