Creating a new directory when objects are created.

What I’m trying to accomplish is when the object is created I want to make a new directory static/images/slug/(images go here). Additionally, I want the directory to be deleted when the object is deleted (I currently delete the images with signals). I’ve read online a few different ways to do it but I haven’t successfully been able to accomplish it. What is the best practice for this to be completed?

class Property(models.Model):
    property_num = models.IntegerField()
    property_road = models.CharField(max_length=200)
    rent = models.IntegerField(default=1000)
    city = models.CharField(max_length=200)
    state = models.CharField(choices=STATE_CHOICE, max_length=25)
    zip = models.IntegerField()
    bedrooms = models.IntegerField()
    bathrooms = models.FloatField(max_length=3)
    sq_foot = models.IntegerField()
    property_title = models.CharField(max_length=200, blank=True, null=True)
    property_short_description = CKEditor5Field('text', config_name='extends', blank = True, null = True)
    description = CKEditor5Field('text', config_name='extends')
    is_active = models.BooleanField(default=True)
    thumbnail = models.ImageField(upload_to='static/images', blank=True)
    slug = models.SlugField(blank=True, null=True, unique=True, allow_unicode=True)
    available_date = models.DateField(max_length=200, blank=True, null=True)

    def __str__(self):
        return '{} {}'.format(self.property_num, self.property_road)

    def address(self):
        return '{} {}'.format(self.property_num, self.property_road)

    def save(self, *args, **kwargs):
        if self.slug is None:
            slug = slugify(self.address)

            has_slug = Property.objects.filter(slug=slug)
            count = 1
            while has_slug:
                count += 1
                slug = slugify(self.address) + '-' + str(count)
                has_slug = Property.objects.filter(slug=slug)
            self.slug = slug
        super().save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('base:properties')

    def file_upload_location(self):
        return 'static/images/{}'.format(self.slug)

class PropertyImage(models.Model):
    property = models.ForeignKey(Property, related_name='images', on_delete=models.CASCADE)
    image = models.ImageField(upload_to='static/images')

Personally, I wouldn’t rely upon signals to do that sort of cleanup. I’d do the clean-up from within the view where the objects being deleted.

(Note: I’m not big fan of using signals in situations other than those areas where they’re necessary. They don’t work in the way that a lot of people think they should work, and do have some hidden gotcha’s. See Django Anti-Patterns: Signals | Lincoln Loop, and Signals ‹ antipattern ‹ Django antipatterns - among other sources for some better details about this.)

What we do is to run a periodic task (weekly) that performs a full clean-up. It takes inventory of all the uploaded files and ensures that there are FileFields referring to them - cleaning up all “orphan” files. (This prevents an accidental deletion in the case where two FileFields are pointing to the same physical file.)

Can you show me an example of this? For the scale of my project, I don’t think it’s gonna make to break anything. It was just a thought I had when I was setting up the server to prevent storing images/videos I’m not going to be using anymore.

I’ll check those out. I actually just found signals a few days ago when I was trying to figure this out on my own so the concept is still fairly new to me.

Do you have any insight about making directories when an object is created?

Getting lists of files and making (and removing) directories are all parts of the standard Python os library.

(Side note: Actually, the project I was thinking of when I wrote that has been retired. We’re not doing that any more. We have migrated to "storing the file contents in the database. It’s not generally considered a “best practice” - but it works for us.)

One thing to keep in mind is that Django can change the name of an uploaded file to make it unique. The file name of an uploaded file written to the file system is not necessarily the name of the file when uploaded through the browser. If that’s information you need to track, you need to track it yourself when the file is uploaded.