0

I've created a basic files app in django so clients can upload files and copy the relative url and use it in the content of the website. One of the ideas of the app was once an entry has been removed the file would be removed from the server, to help clear space and keep the server tidy.

However when i add an entry (file) it uploads to the correct directory. However when i remove it the files remains on the server. Is there a way the file can be removed as well as the entry(file).

Here is the code:

from django.db import models

def get_upload_to(instance, filename):        
    if instance.file_type == 'Image':
        return "images/filesApp/%s" % filename
    elif instance.file_type == 'PDF':
        return "pdf/filesApp/%s" % filename

    return "filesApp/%s" % filename

class File(models.Model):
    title = models.CharField(max_length=400, help_text="Enter the title of the file, this will appear on the listings page")
    CATEGORY_CHOICES = (
        ('Image', 'Image'),
        ('PDF', 'PDF')
    )
    file_type = models.CharField(choices=CATEGORY_CHOICES, help_text="Please select a file type", max_length=200)
    file_upload = models.FileField(upload_to=get_upload_to)

Thanks!

karthikr
  • 97,368
  • 26
  • 197
  • 188
JDavies
  • 2,730
  • 7
  • 34
  • 54
  • Are you after `os.remove` after you've retrieved the file system path for the entry? – Jon Clements May 13 '13 at 16:17
  • Possibly, fairly new to me so you have to elaborate, sorry! I thought it something like .remove() but not sure how i'd target the uploaded file. – JDavies May 13 '13 at 16:19
  • Can you post how you are handling deletes? There's many ways to remove the file, this being one: https://docs.djangoproject.com/en/dev/ref/files/file/#django.core.files.File.delete – Dan Hoerst May 13 '13 at 16:19
  • As for how "target the uploaded file" are you asking what directory/filename it has? Cheeky answer: it's wherever you saved it. And that depends on how you PUT/POST handler works. – Adrian Ratnapala May 13 '13 at 16:22
  • What I didn't know until 3 minutes ago was that Django abstracts the details of `FileField` using a class derived `django.core.files.storage.Storage`. That class has a `.delete` method. BTW: for your kind of app it makes sense to understand this object well, and perhaps even derive your custom version.https://docs.djangoproject.com/en/dev/topics/files/ – Adrian Ratnapala May 13 '13 at 16:27
  • @Paulo and if the method there doesn't work, it still looks like the OP should call `instance.file_upload.storage.delete()` somehow. But I haven't tried it out, so I dare not make this an official answer. – Adrian Ratnapala May 13 '13 at 16:32
  • 2
    @AdrianRatnapala: the way django transactions work, the safer approach is having a cronjob to delete orphaned files above a certain age. – Paulo Scardine May 13 '13 at 16:40
  • Does django include some kind of utility for finding the orphans? – Adrian Ratnapala May 13 '13 at 16:45

1 Answers1

1

Just override the models delete method:

import os
class File(models.Model):
    title = models.CharField(max_length=400, help_text="Enter the title of the file, this will appear on the listings page")
    CATEGORY_CHOICES = (
        ('Image', 'Image'),
        ('PDF', 'PDF')
    )
    file_type = models.CharField(choices=CATEGORY_CHOICES, help_text="Please select a file type", max_length=200)
    file_upload = models.FileField(upload_to=get_upload_to)

    def delete(self, *args, **kwargs):
        path=self.file_upload.path
        os.remove(path)
        super(File,self).delete(*args, **kwargs)

This will work only deleting the entity, not with bulk_delete. If you want to handle those within the admin view, you will have to create a default admin action like this:

from django.contrib import admin
from models import *


def delete_selected(modeladmin, request, queryset):
    for element in queryset:
        element.delete()
delete_selected.short_description = "Delete selected elements"

class FileAdmin(admin.ModelAdmin):
    model = File
    actions = [delete_selected]

    list_display = ('title', 'file_type')

admin.site.register(File, FileAdmin)

Hope it helps!

Paulo Bu
  • 29,294
  • 6
  • 74
  • 73
  • I did give something like this a whirl but not having any luck with it. – JDavies May 13 '13 at 16:37
  • Why not? what happened? – Paulo Bu May 13 '13 at 16:48
  • Nothing all, didn't raise any error. Uploaded the file as normal. Then when i deleted the entry, the file stayed in the folder. – JDavies May 13 '13 at 16:50
  • Perform some debug to see if the code is working, for example, raise an exception inside the delete method and see if it raises. – Paulo Bu May 13 '13 at 16:52
  • Am i right in saying the code above will delete the path to the file to? – JDavies May 13 '13 at 17:00
  • Will delete the file where `path` points to. Also, you can try instead of `storage`, use `os.remove` like this `os.remove(path)` – Paulo Bu May 13 '13 at 17:03
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/29863/discussion-between-josh-davies-and-paulo-bu) – JDavies May 13 '13 at 17:11
  • 1
    You may also wish to use a `post_delete` signal handler which will work for both single instance deletes and bulk deletes. – Brian Neal May 14 '13 at 00:48